├── .editorconfig ├── .gitattributes ├── .gitignore ├── CHANGELOG ├── LICENSE ├── README.rst ├── docs ├── .gitignore ├── _static │ └── linuxdoc.css ├── cmd-line.rst ├── cmd-line │ ├── linuxdoc.autodoc.rst │ ├── linuxdoc.lintdoc.rst │ └── linuxdoc.rest.rst ├── conf.py ├── darmarIT_logo_128.png ├── downloads │ └── patch_linux.patch ├── index.rst ├── install.rst ├── kernel-doc-intro.rst ├── linuxdoc-howto │ ├── all-in-a-tumble-debug.rst │ ├── all-in-a-tumble-src.rst │ ├── all-in-a-tumble.c │ ├── all-in-a-tumble.h │ ├── all-in-a-tumble.rst │ ├── cdomain.rst │ ├── csv_table.txt │ ├── hello.dot │ ├── index.rst │ ├── kernel-doc-directive.rst │ ├── kernel-doc-examples.rst │ ├── kernel-doc-modes.rst │ ├── kernel-doc-syntax.rst │ ├── kernel-doc-tests.rst │ ├── kernel-include-directive.rst │ ├── kfigure.rst │ ├── man-pages.rst │ ├── reST-kernel-doc-mode.rst │ ├── refs.txt │ ├── svg_image.svg │ ├── table-markup.rst │ ├── test_internals.c │ ├── test_internals.h │ └── vintage-kernel-doc-mode.rst └── refs.txt ├── kernel-docgrep ├── linuxdoc ├── __init__.py ├── __pkginfo__.py ├── autodoc.py ├── cdomain.py ├── cdomainv2.py ├── cdomainv3.py ├── compat.py ├── deprecated.py ├── grepdoc.py ├── kernel_doc.py ├── kernel_include.py ├── kfigure.py ├── lint.py ├── manKernelDoc.py ├── rest.py ├── rstFlatTable.py └── rstKernelDoc.py ├── prj ├── pylintrc.toml ├── pyproject.toml ├── pyrightconfig.json ├── scripts ├── Makefile ├── lib_doc-sphinx.sh ├── lib_msg.sh ├── lib_sh.sh ├── lib_tui.sh └── main.sh └── tests └── __init__.py /.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 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | utils/* linguist-vendored 2 | Makefile linguist-vendored 3 | .dir-locals.el linguist-vendored 4 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | linuxdoc-api/ 2 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /docs/darmarIT_logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/return42/linuxdoc/401c50df9b0cc3f0ef4e7b7f85e637d53f42839b/docs/darmarIT_logo_128.png -------------------------------------------------------------------------------- /docs/downloads/patch_linux.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Documentation/Makefile b/Documentation/Makefile 2 | index e889e7cb8511..64c56e698697 100644 3 | --- a/Documentation/Makefile 4 | +++ b/Documentation/Makefile 5 | @@ -41,7 +41,7 @@ PAPEROPT_a4 = -D latex_paper_size=a4 6 | PAPEROPT_letter = -D latex_paper_size=letter 7 | KERNELDOC = $(srctree)/scripts/kernel-doc 8 | KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC) 9 | -ALLSPHINXOPTS = $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) 10 | +ALLSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) 11 | # the i18n builder cannot share the environment and doctrees with the others 12 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 13 | 14 | @@ -72,6 +72,9 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) 15 | htmldocs: 16 | @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) 17 | 18 | +mandocs: 19 | + @$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,kernel-doc-man,$(var),man,$(var))) 20 | + 21 | linkcheckdocs: 22 | @$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,linkcheck,$(var),,$(var))) 23 | 24 | diff --git a/Documentation/conf.py b/Documentation/conf.py 25 | index 72647a38b5c2..0b049b0dff4b 100644 26 | --- a/Documentation/conf.py 27 | +++ b/Documentation/conf.py 28 | @@ -34,13 +34,16 @@ needs_sphinx = '1.3' 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | -extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure', 'sphinx.ext.ifconfig'] 33 | - 34 | -# The name of the math extension changed on Sphinx 1.4 35 | -if major == 1 and minor > 3: 36 | - extensions.append("sphinx.ext.imgmath") 37 | -else: 38 | - extensions.append("sphinx.ext.pngmath") 39 | +extensions = [ 40 | + 'linuxdoc.rstFlatTable' # flat-table reST directive 41 | + , 'linuxdoc.rstKernelDoc' # kernel-doc reST directive 42 | + , 'linuxdoc.manKernelDoc' # kernel-doc-man sphinx builder 43 | + , 'linuxdoc.cdomain' # Replacement for the sphinx c-domain 44 | + , 'linuxdoc.kfigure' # Sphinx extension which implements scalable image handling 45 | + , 'linuxdoc.kernel_include' 46 | + , 'sphinx.ext.todo' 47 | + , 'sphinx.ext.imgmath' 48 | +] 49 | 50 | # Add any paths that contain templates here, relative to this directory. 51 | templates_path = ['_templates'] 52 | @@ -132,7 +135,7 @@ pygments_style = 'sphinx' 53 | #keep_warnings = False 54 | 55 | # If true, `todo` and `todoList` produce output, else they produce nothing. 56 | -todo_include_todos = False 57 | +todo_include_todos = True 58 | 59 | primary_domain = 'c' 60 | highlight_language = 'none' 61 | @@ -434,10 +437,7 @@ latex_documents = [ 62 | 63 | # One entry per manual page. List of tuples 64 | # (source start file, name, description, authors, manual section). 65 | -man_pages = [ 66 | - (master_doc, 'thelinuxkernel', 'The Linux Kernel Documentation', 67 | - [author], 1) 68 | -] 69 | +man_pages = [] 70 | 71 | # If true, show URL addresses after external links. 72 | #man_show_urls = False 73 | @@ -551,11 +551,66 @@ pdf_documents = [ 74 | ('kernel-documentation', u'Kernel', u'Kernel', u'J. Random Bozo'), 75 | ] 76 | 77 | -# kernel-doc extension configuration for running Sphinx directly (e.g. by Read 78 | -# the Docs). In a normal build, these are supplied from the Makefile via command 79 | -# line arguments. 80 | -kerneldoc_bin = '../scripts/kernel-doc' 81 | -kerneldoc_srctree = '..' 82 | +# ------------------------------------------------------------------------------ 83 | +# Options of the kernel-doc parser 84 | +# ------------------------------------------------------------------------------ 85 | + 86 | +# Set parser's default value for kernel-doc directive option ``:exp-method:`` 87 | +# default: kernel_doc_exp_method = 'macro' 88 | + 89 | +# Set parser's default value for kernel-doc directive option ``:exp-ids:``. 90 | +# default: kernel_doc_exp_ids = \ 91 | +# ['EXPORT_SYMBOL', 'EXPORT_SYMBOL_GPL', 'EXPORT_SYMBOL_GPL_FUTURE'] 92 | + 93 | +# Set parser's default value for kernel-doc directive option ``:known-attrs:`` 94 | +# default: kernel_doc_known_attrs = [...] 95 | + 96 | +# Global fallback for man section of kernel-doc directives. Set this value if 97 | +# you want to create man pages for those kernel-doc directives, which has not 98 | +# been set a ``:man-sect:`` value. The default is ``None``, which means; do the 99 | +# opposite and create only man pages for those directives which has been set the 100 | +# ``:man-sect:`` option. 101 | +# default: kernel_doc_mansect = None 102 | +kernel_doc_mansect = 9 103 | + 104 | +# Set parser's default kernel-doc mode ``[reST|kernel-doc]``. Normally you wont 105 | +# set anything other than the default! 106 | +# default: kernel_doc_mode = 'reST' 107 | + 108 | +# If true, more warnings will be logged. E.g. a missing description of a 109 | +# function's return value will be logged. 110 | +# default: kernel_doc_verbose_warn = True 111 | +kernel_doc_verbose_warn = False 112 | + 113 | +# If ``True`` fatal errors (like missing function descriptions) raise an error. 114 | +# The default is ``True``. This means that the build process break every time a 115 | +# serve error in the documentation build occur. Often it might be better the 116 | +# build continues and inserts Oops on serve errors. For this, set 117 | +# ``kernel_doc_raise_error`` to ``False``. 118 | +# default kernel_doc_raise_error = True 119 | +kernel_doc_raise_error = False 120 | + 121 | +# Oops messages are Sphinx ``.. todo::`` directives. To insert the Oops 122 | +# messages from the kernel-doc parser we have to active todo_include_todos also. 123 | +todo_include_todos = True 124 | + 125 | +# In nickpick mode, it will complain about lots of missing references that 126 | +# 127 | +# 1) are just typedefs like: bool, __u32, etc; 128 | +# 2) It will complain for things like: enum, NULL; 129 | +# 3) It will complain for symbols that should be on different 130 | +# books (but currently aren't ported to ReST) 131 | +# 132 | +# The list below has a list of such symbols to be ignored in nitpick mode 133 | +# 134 | +nitpick_ignore = [ 135 | + ("c:type", "bool"), 136 | + ("c:type", "enum"), 137 | + ("c:type", "u16"), 138 | + ("c:type", "u32"), 139 | + ("c:type", "u64"), 140 | + ("c:type", "u8"), 141 | + ] 142 | 143 | # ------------------------------------------------------------------------------ 144 | # Since loadConfig overwrites settings from the global namespace, it has to be 145 | diff --git a/Documentation/media/Makefile b/Documentation/media/Makefile 146 | index d75d70f191bc..ee28d6fee1bb 100644 147 | --- a/Documentation/media/Makefile 148 | +++ b/Documentation/media/Makefile 149 | @@ -57,6 +57,7 @@ $(BUILDDIR)/lirc.h.rst: ${UAPI}/lirc.h ${PARSER} $(SRC_DIR)/lirc.h.rst.exception 150 | 151 | all: $(IMGDOT) $(BUILDDIR) ${TARGETS} 152 | html: all 153 | +kernel-doc-man: all 154 | epub: all 155 | xml: all 156 | latex: $(IMGPDF) all 157 | diff --git a/Makefile b/Makefile 158 | index a45f84a7e811..8e015889fb9b 100644 159 | --- a/Makefile 160 | +++ b/Makefile 161 | @@ -1543,6 +1543,7 @@ $(help-board-dirs): help-%: 162 | # Documentation targets 163 | # --------------------------------------------------------------------------- 164 | DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs \ 165 | + mandocs \ 166 | linkcheckdocs dochelp refcheckdocs 167 | PHONY += $(DOC_TARGETS) 168 | $(DOC_TARGETS): scripts_basic FORCE 169 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /docs/kernel-doc-intro.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: linuxdoc-howto/refs.txt 3 | 4 | .. _kernel-doc-intro: 5 | 6 | ======================= 7 | kernel-doc introduction 8 | ======================= 9 | 10 | In order to embed **"C" friendly** and extractable documentation into C/C++ 11 | source code comments, the Kernel community adopted a consistent style for 12 | documentation comments. The markup for this documentation is called the 13 | **kernel-doc markup**. This style embeds the documentation within the source 14 | files, using a few simple conventions for adding documentation paragraphs and 15 | documenting functions and their parameters, structures, unions and their 16 | members, enumerations, and typedefs. It also includes lightweight markups for 17 | highlights and cross-references in your source code. 18 | 19 | The kernel-doc format is deceptively similar to Doxygen, javadoc or `Sphinx's 20 | autodoc`_ which grabs for comments in `Sphinx's Python domain`_. The kernel-doc 21 | format has a long tradition, e.g. its also well highlighted in your emacs ;) If 22 | you are familiar with Sphinx_, you might know about `Sphinx's C domain`_ markup. 23 | 24 | .. note:: 25 | 26 | - Compared `Sphinx's C domain`_, the :ref:`kernel-doc-syntax` is less verbose 27 | and much more coder friendly (:ref:`kernel-doc comment 28 | ` and :ref:`reST `). 29 | 30 | - The opening comment mark ``/**`` is reserved for kernel-doc comments. 31 | 32 | The **kernel-doc parser** of the LinuxDoc package grabs the documentation from 33 | your C sources and translates the **kernel-doc markup** into proper reST_. From 34 | coder's POV, the C-friendly kernel-doc markup is translated into the more 35 | verbosely `Sphinx's C domain`_ which can be included at any place in the 36 | documentation. 37 | 38 | Only comments so marked will be considered by the kernel-doc tools, and any 39 | comment so marked must be in kernel-doc format. The closing comment marker for 40 | kernel-doc comments can be either ``*/`` or ``**/``, but ``*/`` is preferred in 41 | the Linux kernel tree. The lines in between should be prefixed by `` * `` 42 | (space star space). 43 | 44 | .. _kernel-doc-intro-example: 45 | 46 | by example 47 | ========== 48 | 49 | Lets start with a simple example, documenting our elaborate *foobar* function. 50 | 51 | .. code-block:: c 52 | 53 | /** 54 | * foobar() - short function description of foobar 55 | * 56 | * @arg1: Describe the first argument to foobar. 57 | * @arg2: Describe the second argument to foobar. One can provide multiple line 58 | * descriptions for arguments. 59 | * 60 | * A longer description, with more discussion of the function foobar() that 61 | * might be useful to those using or modifying it. Begins with empty comment 62 | * line and may include additional embedded empty comment lines. Within, you 63 | * can refer other definitions (e.g. &struct my_struct, &typedef my_typedef, 64 | * %CONSTANT, $ENVVAR etc.). 65 | * 66 | * The longer description can have multiple paragraphs and you can use reST 67 | * inline markups like *emphasise* and **emphasis strong**. You also have reST 68 | * block markups like lists or literal available: 69 | * 70 | * Ordered List: 71 | * - item one 72 | * - item two 73 | * - literal block:: 74 | * 75 | * a + b --> x 76 | * 77 | * Return: 78 | * Describe the return value of foobar. 79 | */ 80 | int foobar(int arg1, int arg2); 81 | 82 | Pause here and recap what we have seen in the example above. It is a mix-up of 83 | kernel-doc markup and reST_ markup. Markups like the function description in 84 | the first line and the following argument descriptions are covered by the 85 | kernel-doc markup, while other markups like the ordered list, the literal block 86 | or the inline emphasis are all a part of the reST_ markup. The combination of 87 | these markups enables us to write compact (*"C" friendly*) documentation within 88 | the source code. 89 | 90 | From coder's point, we made a great job documenting our ``foorbar()`` function. 91 | Now lets take the POV of an author who like to use this description in his 92 | detailed API documentation. This is where the :ref:`kernel-doc directive 93 | ` comes in use. To include the ``foobar()`` description, 94 | which might be located in file ``include/foobar.h``, the author can use the 95 | kernel-doc directive like this: 96 | 97 | .. code-block:: rst 98 | 99 | .. kernel-doc:: include/foobar.h 100 | :symbols: foobar 101 | 102 | Now, if the documentation build process takes places, the kernel-doc directive 103 | runs the **kernel-doc parser** which grabs the documentation and translates the 104 | **kernel-doc markup** into proper reST_. Within the output, the directive is 105 | replaced by the generated reST_. Later we will see some rendered examples, here 106 | to complete the example lets take a look at the generated doctree, printed out 107 | in reST_ format: 108 | 109 | .. _kernel-doc-intro-example-out: 110 | 111 | .. code-block:: rst 112 | 113 | .. _`foobar`: 114 | 115 | foobar 116 | ====== 117 | 118 | .. c:function:: int foobar(int arg1, int arg2) 119 | 120 | short function description of foobar 121 | 122 | :param int arg1: 123 | Describe the first argument to foobar. 124 | 125 | :param int arg2: 126 | Describe the second argument to foobar. One can provide multiple line 127 | descriptions for arguments. 128 | 129 | .. _`foobar.description`: 130 | 131 | Description 132 | ----------- 133 | 134 | A longer description, with more discussion of the function :c:func:`foobar` 135 | that might be useful to those using or modifying it. Begins with empty 136 | comment line, and may include additional embedded empty comment lines. 137 | Within you can refer other definitions (e.g. :c:type:`struct my_struct 138 | `, :c:type:`typedef my_typedef `, ``CONSTANT``, 139 | ``$ENVVAR`` etc.). 140 | 141 | The longer description can have multiple paragraphs and you can use reST 142 | inline markups like *emphasise* and **emphasis strong**. You also have reST 143 | 144 | .. _`foobar.ordered-list`: 145 | 146 | Ordered List 147 | ------------ 148 | 149 | 150 | - item one 151 | - item two 152 | - literal block:: 153 | 154 | a + b --> x 155 | 156 | .. _`foobar.return`: 157 | 158 | Return 159 | ------ 160 | 161 | Describe the return value of foobar. 162 | 163 | 164 | Compare this reST with the kernel-doc comment from the beginning. This reST is 165 | what you have to type if do not have kernel-doc markups, isn't it coder 166 | friendly? If you look closer, you will also see that there is a subsection 167 | named *Ordered List*. Be not surprised, this subsection is also made by a 168 | kernel-doc markup, read on in the the :ref:`kernel-doc-syntax` chapter for a 169 | detailed description of the markup. 170 | 171 | So far we have hyped the kernel-doc, to be complete we also have to look what 172 | the drawbacks and restrictions are. In your daily work you won’t discover any 173 | huge drawback, but you will be aware of some restrictions. These are given by 174 | the fact, that in some circumstances the mix of the very condensed kernel-doc 175 | markup and the reST markup will bite each other. There you will need some 176 | quotes (``\``) to escape, that might partial cutting your joy in kernel-doc. 177 | Anyway, overall you should be able to recognize the daily benefit of using 178 | kernel-doc markup in your projects. 179 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/hello.dot: -------------------------------------------------------------------------------- 1 | graph G { 2 | Hello -- World 3 | } 4 | -------------------------------------------------------------------------------- /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/kernel-doc-directive.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _conf.py: http://www.sphinx-doc.org/en/stable/config.html 5 | 6 | .. _kernel-doc-directive: 7 | 8 | ============================ 9 | kernel-doc in reST documents 10 | ============================ 11 | 12 | To integrate :ref:`kernel-doc ` comments into a reST document 13 | (e.g. in a *book*), there exists a reST-directive_ named ``kernel-doc`` . The 14 | directive comes with options to fine grain control which parts should be placed 15 | into the reST document. With no options given, the complete kernel-doc comments 16 | from a source file will be inserted. So, the first and very simple example is: 17 | 18 | .. code-block:: rst 19 | 20 | My Lib 21 | ====== 22 | 23 | .. kernel-doc:: ../src/mylib.h 24 | 25 | 26 | With this small example (a file ``doc/mylib.rst``) the kernel-doc comments from 27 | the ``src/mylib.h`` will be inserted direct under the chapter "My Lib". The 28 | "DOC:" sections, the function and the type descriptions will be inserted in the 29 | order they appear in the source file. Mostly you want to select more fine 30 | grained, read on to see how. 31 | 32 | .. _kernel-doc-options: 33 | 34 | kernel-doc options 35 | ================== 36 | 37 | Here is a short overview of the directives options: 38 | 39 | .. code-block:: rst 40 | 41 | .. kernel-doc:: 42 | :doc:
43 | :no-header: 44 | :export: 45 | :internal: 46 | :exp-method: 47 | :exp-ids: 48 | :symbols: 49 | :module: 50 | :man-sect: 51 | :snippets: 52 | :language: 53 | :linenos: 54 | :debug: 55 | 56 | The argument ```` is required and points to the source file. The 57 | pathname is relative to the pathname of the ``kernel-doc`` directive. Absolute 58 | pathnames are relative to ``srctree``, which can be set in the environment or 59 | using :ref:`kernel_doc_srctree ` in the sphinx conf.py_ (if 60 | unset, defaults to CWD). The options have the following meaning, but be aware 61 | that not all combinations of these options make sense: 62 | 63 | ``:doc:
`` (:ref:`doc_sections`) 64 | Include content of the ``DOC:`` section titled ``
``. Spaces 65 | are allowed in ``
``; do not quote the ``
``. 66 | 67 | The next option make only sense in conjunction with option ``doc``: 68 | 69 | ``:no-header:`` (:ref:`opt_no-header`) 70 | Do not output DOC: section's title. Useful, if the surrounding context 71 | already has a heading, and the DOC: section title is only used as an 72 | identifier. Take in mind, that this option will not suppress any native 73 | reST heading markup in the comment. 74 | 75 | ``:export: [ [, ...]]`` (:ref:`opt_export`) 76 | Include documentation of all function, struct or whatever definitions in 77 | ```` and exported using one of the :ref:`export symbols ` (:ref:`macro `) either in ```` or in 79 | any of the files specified by ````. 80 | 81 | The ```` (glob) is useful when the kernel-doc comments 82 | have been placed in header files, while *EXPORT_SYMBOL* are next to the 83 | function definitions. 84 | 85 | ``:internal: [ [, ...]]`` (:ref:`opt_internal`) 86 | Include documentation of all documented definitions, **not** exported by one 87 | of the :ref:`export symbols ` (:ref:`macro `) either in ```` or in any of the files specified by 89 | ````. 90 | 91 | .. _exp-method option: 92 | 93 | ``:exp-method: `` 94 | Change the way exported symbols are specified in source code. Default value 95 | ``macro`` if not provided, can be set globally by 96 | :ref:`kernel_doc_exp_method ` in the sphinx conf.py_. 97 | 98 | 99 | The ```` must one of 100 | the following value: 101 | 102 | ``macro`` 103 | Exported symbols are specified by macros (whose names are controlled by 104 | ``exp-ids`` option) invoked in the source the following way: 105 | ``THIS_IS_AN_EXPORTED_SYMBOL(symbol)`` 106 | 107 | ``attribute`` 108 | Exported symbols are specified definition using a specific attribute 109 | (controlled by ``exp-ids`` option) either in their declaration or 110 | definition: ``THIS_IS_AN_EXPORTED_SYMBOL int symbol(void* some_arg) 111 | {...}`` 112 | 113 | .. _exp-ids option: 114 | 115 | ``:exp-ids: `` 116 | Use the specified list of identifiers instead of default value: ``EXPORT_SYMBOL``, 117 | ``EXPORT_SYMBOL_GPL`` & ``EXPORT_SYMBOL_GPL_FUTURE``. Default value 118 | can be overriden globally by sphinx conf.py_ option :ref:`kernel_doc_exp_ids 119 | `. 120 | 121 | ``:known-attrs: `` 122 | Specified a list of function attributes that are known and must be hidden 123 | when displaying function prototype. 124 | 125 | When ``:exp-method:`` is set to ``attribute`` the list in ``:exp-ids:`` is 126 | considered as known and added implicitly to this list of known attributes. 127 | The default list is empty and can be adjusted by the sphinx configuration 128 | option :ref:`kernel_doc_known_attrs `. 129 | 130 | ``:symbols: `` (:ref:`kernel-doc-functions`, :ref:`kernel-doc-structs`) 131 | Include documentation for each named definition. For backward compatibility 132 | there exists an alias ``functions``. 133 | 134 | ``:module: `` 135 | The option ``:module: `` sets a module-name and is used in 136 | ``.. c:namespace-push:`` `[ref] `__. The module-name 137 | (aka *namespace*) is used as a prefix in the cross links. For a detailed 138 | example have a look at section :ref:`kernel-doc-functions`. 139 | 140 | ``:man-sect: `` 141 | Section number of the manual pages (see "``$ man man-pages``""). Optional set 142 | :ref:`kernel_doc_mansect ` option in sphinx conf.py_. The 143 | man-pages are build by the ``kernel-doc-man`` builder. Read on here: 144 | :ref:`man-pages` 145 | 146 | ``:snippets: `` 147 | Inserts the source-code passage(s) marked with the snippet ``name``. The 148 | snippet is inserted with a `code-block:: `_ 149 | directive. 150 | 151 | The next options make only sense in conjunction with option ``snippets``: 152 | 153 | ``language `` 154 | Set highlighting language of the snippet code-block. 155 | 156 | ``linenos`` 157 | Set line numbers in the snippet code-block. 158 | 159 | ``:debug:`` 160 | Inserts a code-block with the generated reST source. This might sometimes 161 | helpful to see how the kernel-doc parser transforms the kernel-doc markup to 162 | reST markup. 163 | 164 | 165 | .. _kernel-doc-functions: 166 | 167 | Insert function's documentation 168 | =============================== 169 | 170 | In :ref:`all-in-a-tumble.c-src` there is the following function definition which 171 | is documented by a :ref:`kernel-doc-syntax`. 172 | 173 | .. kernel-doc:: ./all-in-a-tumble.c 174 | :snippets: user_function 175 | :language: c 176 | 177 | To include the documentation from C-:ref:`kernel-doc-syntax-functions` into your 178 | reStructuredText document use the following markup: 179 | 180 | .. code-block:: rst 181 | 182 | .. kernel-doc:: ./all-in-a-tumble.c 183 | :symbols: user_function 184 | :module: foo 185 | 186 | This will convert the :ref:`kernel-doc-syntax` into the following reST markup: 187 | 188 | .. kernel-doc:: ./all-in-a-tumble.c 189 | :symbols: user_function 190 | :module: foo 191 | :debug: 192 | 193 | ---- 194 | 195 | In the next view lines you will see how the documentation will be rendered: 196 | 197 | .. admonition:: kernel-doc option ``:symbols:`` 198 | :class: rst-example 199 | 200 | .. kernel-doc:: ./all-in-a-tumble.c 201 | :symbols: user_function 202 | :module: foo 203 | 204 | In reST documents you can cross reference to the function or directly to one of 205 | the sections of this documentation: 206 | 207 | .. code-block:: rst 208 | 209 | * C constructs in Sphinx >= 3.1 :c:func:`foo.user_function` 210 | * refer sections: :ref:`Example `, 211 | :ref:`Return ` ... 212 | 213 | .. admonition:: cross referencing function's documentation 214 | :class: rst-example 215 | 216 | * C constructs in Sphinx >= 3.1 :c:func:`foo.user_function` 217 | * refer sections: :ref:`Example `, 218 | :ref:`Return ` ... 219 | 220 | 221 | .. _kernel-doc-structs: 222 | .. _kernel-doc-unions: 223 | .. _kernel-doc-enums: 224 | .. _kernel-doc-typedefs: 225 | 226 | structs, unions, enums and typedefs 227 | =================================== 228 | 229 | The following example inserts the documentation of struct ``my_long_struct``. 230 | 231 | .. code-block:: rst 232 | 233 | .. kernel-doc:: ./all-in-a-tumble.h 234 | :symbols: my_long_struct 235 | :module: example 236 | 237 | Here in this documentation the examples from the :ref:`all-in-a-tumble-src` are 238 | located in the ``example`` module (aka *namespace*). To `Cross-referencing C 239 | constructs`_ within this module you can use the Sphinx *namespace* or to point 240 | to a section you can use the anchors inserted by the ``.. kernel-doc::`` 241 | directive. 242 | 243 | .. code-block:: rst 244 | 245 | * C constructs in Sphinx >= 3.1 :c:struct:`example.my_long_struct` 246 | * refer sections: :ref:`Definition `, 247 | :ref:`Members ` ... 248 | 249 | .. admonition:: option ``:symbols: structs, unions, enums and typedefs`` 250 | :class: rst-example 251 | 252 | * C constructs in Sphinx >= 3.1 :c:struct:`example.my_long_struct` 253 | * refer sections: :ref:`Definition `, 254 | :ref:`Members ` ... 255 | 256 | .. _kernel-doc-snippets: 257 | 258 | Snippets 259 | ======== 260 | 261 | The kernel-doc Parser supports a markup for :ref:`kernel-doc-syntax-snippets`. 262 | By example; In the the :ref:`all-in-a-tumble examples ` 263 | we have a small source code example: 264 | 265 | .. code-block:: c 266 | 267 | /* parse-SNIP: hello-world */ 268 | #include 269 | int main() { 270 | printf("Hello World\n"); 271 | return 0; 272 | } 273 | /* parse-SNAP: */ 274 | 275 | To insert the code passage between SNIP & SNAP use: 276 | 277 | .. code-block:: rst 278 | 279 | .. kernel-doc:: ./all-in-a-tumble.c 280 | :snippets: hello-world 281 | :language: c 282 | :linenos: 283 | 284 | And here is the rendered example: 285 | 286 | .. kernel-doc:: ./all-in-a-tumble.c 287 | :snippets: hello-world 288 | :language: c 289 | :linenos: 290 | 291 | .. _kernel-doc-man-sect: 292 | 293 | man pages (:man-sect:) 294 | ====================== 295 | 296 | To get man pages from kernel-doc comments, add the ``:man-sect:`` option to your 297 | kernel-doc directives. E.g. to get man-pages of media's remote control (file 298 | ``media/kapi/rc-core.rst``) add ``:man-sect: 9`` to all the kernel-doc includes. 299 | 300 | .. code-block:: rst 301 | 302 | Remote Controller devices 303 | ========================= 304 | 305 | Remote Controller core 306 | ---------------------- 307 | 308 | .. kernel-doc:: include/media/rc-core.h 309 | :man-sect: 9 310 | 311 | .. kernel-doc:: include/media/rc-map.h 312 | :man-sect: 9 313 | 314 | LIRC 315 | ---- 316 | 317 | .. kernel-doc:: include/media/lirc_dev.h 318 | :man-sect: 9 319 | 320 | If you don't want to edit all your kernel-doc directives to get man page from, 321 | set a global man-sect in your ``conf.py``, see sphinx configuration 322 | :ref:`kernel_doc_mansect ` and about build look at: 323 | :ref:`man-pages` 324 | 325 | Highlights and cross-references 326 | =============================== 327 | 328 | The following special patterns are recognized in the kernel-doc comment 329 | descriptive text and converted to proper reStructuredText markup and `Sphinx's C 330 | Domain`_ references. 331 | 332 | .. attention:: 333 | 334 | The below are **only** recognized within kernel-doc comments, **not** within 335 | normal reStructuredText documents. 336 | 337 | ``funcname()`` 338 | Function reference. 339 | 340 | ``@parameter`` 341 | Name of a function parameter. (No cross-referencing, just formatting.) 342 | 343 | ``%CONST`` 344 | Name of a constant. (No cross-referencing, just formatting.) 345 | 346 | ````literal```` 347 | A literal block that should be handled as-is. The output will use a 348 | ``monospaced font``. 349 | 350 | Useful if you need to use special characters that would otherwise have some 351 | meaning either by kernel-doc script of by reStructuredText. 352 | 353 | This is particularly useful if you need to use things like ``%ph`` inside 354 | a function description. 355 | 356 | ``$ENVVAR`` 357 | Name of an environment variable. (No cross-referencing, just formatting.) 358 | 359 | ``&struct name`` 360 | Structure reference. 361 | 362 | ``&enum name`` 363 | Enum reference. 364 | 365 | ``&typedef name`` 366 | Typedef reference. 367 | 368 | ``&struct_name->member`` or ``&struct_name.member`` 369 | Structure or union member reference. The cross-reference will be to the struct 370 | or union definition, not the member directly. 371 | 372 | ``&name`` 373 | A generic type reference. Prefer using the full reference described above 374 | instead. This is mostly for legacy comments. 375 | 376 | .. _kernel-doc-config: 377 | 378 | kernel-doc config 379 | ================= 380 | 381 | Within the `sphinx config`_ file (``conf.py`` or ``my_project.conf``) you can 382 | set the following option. 383 | 384 | .. _kernel_doc_exp_method: 385 | 386 | kernel_doc_exp_method: :py:obj:`linuxdoc.kernel_doc.DEFAULT_EXP_METHOD` 387 | Set parser's default value for kernel-doc directive option ``:exp-method:`` 388 | (details see: :ref:`exp-method `) 389 | 390 | .. _kernel_doc_exp_ids: 391 | 392 | kernel_doc_exp_ids: :py:obj:`linuxdoc.kernel_doc.DEFAULT_EXP_IDS` 393 | Set parser's default value for kernel-doc directive option ``:exp-ids:``. 394 | (details see: :ref:`exp-ids `) 395 | 396 | kernel_doc_known_attrs: ``[...]`` 397 | Set parser's default value for kernel-doc directive option ``:known-attrs:`` 398 | (details see: :ref:`kernel-doc-options`) 399 | 400 | kernel_doc_mansect: ``None`` 401 | Global fallback for man section of kernel-doc directives. Set this value if 402 | you want to create man pages for those kernel-doc directives, which has not 403 | been set a ``:man-sect:`` value. The default is ``None``, which means; do the 404 | opposite and create only man pages for those directives which has been set the 405 | ``:man-sect:`` option (``None`` is what you mostly want). 406 | 407 | kernel_doc_mode: ``reST`` 408 | Set parser's default kernel-doc mode ``[reST|kernel-doc]``. Normally you wont 409 | set anything other than the default! See :ref:`reST-kernel-doc-mode` and 410 | :ref:`vintage-kernel-doc-mode`. 411 | 412 | kernel_doc_verbose_warn: ``True`` 413 | If true, more warnings will be logged. E.g. a missing description of a 414 | function's return value will be logged. 415 | 416 | kernel_doc_raise_error: ``True`` 417 | If ``True`` fatal errors (like missing function descriptions) raise an error. 418 | The default is ``True``. This means that the build process break every time a 419 | serve error in the documentation build occur. Often it might be better the 420 | build continues and inserts Oops on serve errors. For this, set 421 | ``kernel_doc_raise_error`` to ``False``. In the next example, the 422 | documentation of a non existing definition name ``no_longer_exists`` is 423 | required: 424 | 425 | .. code-block:: rst 426 | 427 | .. kernel-doc:: ./all-in-a-tumble.h 428 | :symbols: no_longer_exist 429 | 430 | Since this definition not exists (anymore), the following TODO entry with Oops 431 | is inserted (again; only when ``kernel_doc_raise_error`` is ``False``). 432 | 433 | .. admonition:: parser error inserts a ".. todo::" directive with *Oops* in 434 | :class: rst-example 435 | 436 | .. kernel-doc:: ./all-in-a-tumble.h 437 | :symbols: no_longer_exist 438 | 439 | kernel_doc_srctree: ``None`` 440 | Set the pathname used as a base for absolute pathnames in kernel-doc 441 | directive. It can be overridden by the ``srctree`` environment variable. 442 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/kernel-doc-syntax.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _kernel-doc-syntax: 5 | 6 | ================= 7 | kernel-doc syntax 8 | ================= 9 | 10 | The format of a block comment is like this:: 11 | 12 | /** 13 | * (data-type|DOC)? name(:)? (- short description)? 14 | (* @x: (description of parameter/member x)?)* 15 | (* a blank line)? 16 | * (Description of function or data structure)? 17 | (* a blank line)? 18 | * (sub-section header: 19 | * (sub-section description) )* 20 | (*)?*/ 21 | 22 | 23 | * ``(...)?`` signifies optional structure and 24 | * ``(...)*`` signifies 0 or more structure elements 25 | 26 | The name of the function, data-type respectively DOC is used as the section 27 | header. The names of section headers must be unique per source file. 28 | 29 | .. _kernel-doc-syntax-functions: 30 | 31 | functions 32 | ========= 33 | 34 | :: 35 | 36 | /** 37 | * function_name(:)? (- short description)? 38 | (* @parameterx: (description of parameter x)?)* 39 | (* a blank line)? 40 | * (Description of function)? 41 | (* a blank line)? 42 | * (sub-section header: 43 | * (sub-section description) )* 44 | (*)?*/ 45 | 46 | All *description* text can span multiple lines, although the ``function_name`` & 47 | its short description are traditionally on a single line. Description text may 48 | also contain blank lines (i.e., lines that contain only a "*"). 49 | 50 | So, the trivial example would be: 51 | 52 | .. code-block:: c 53 | 54 | /** 55 | * my_function 56 | */ 57 | 58 | If the Description: header tag is omitted, then there must be a blank line 59 | after the last parameter specification.: 60 | 61 | .. code-block:: c 62 | 63 | /** 64 | * my_function - does my stuff 65 | * @my_arg: its mine damnit 66 | * 67 | * Does my stuff explained. 68 | */ 69 | 70 | or, could also use: 71 | 72 | .. code-block:: c 73 | 74 | /** 75 | * my_function - does my stuff 76 | * @my_arg: its mine damnit 77 | * Description: 78 | * Does my stuff explained. 79 | */ 80 | 81 | You can also add additional sections. When documenting kernel functions you 82 | should document the ``Context:`` of the function, e.g. whether the functions can 83 | be called form interrupts. Unlike other sections you can end it with an empty 84 | line. 85 | 86 | A non-void function should have a ``Return:`` section describing the return 87 | value(s). Example-sections should contain the string ``EXAMPLE`` so that 88 | they are marked appropriately in the output format. 89 | 90 | .. kernel-doc:: ./all-in-a-tumble.c 91 | :snippets: user_function 92 | :language: c 93 | :linenos: 94 | 95 | Rendered example: :ref:`example.user_function` 96 | 97 | .. _kernel-doc-syntax-macro: 98 | 99 | macro 100 | ===== 101 | 102 | Documenting macros is similar to documenting :ref:`kernel-doc-syntax-functions`. 103 | 104 | .. kernel-doc:: ./all-in-a-tumble.h 105 | :snippets: ADD_macro 106 | :language: c 107 | :linenos: 108 | 109 | Rendered example: :ref:`example.ADD` 110 | 111 | .. _kernel-doc-syntax-structs-unions: 112 | 113 | structs, unions 114 | =============== 115 | 116 | Beside functions you can also write documentation for ``structs``, 117 | ``unions``. Instead of the function name you must write the name of the 118 | declaration; the ``struct`` or ``union`` must always precede the name. Nesting 119 | of declarations is supported. Use the ``@argument`` mechanism to document 120 | members or constants. 121 | 122 | Inside a ``struct`` description, you can use the 'private:' and 'public:' comment 123 | tags. Structure fields that are inside a 'private:' area are not listed in the 124 | generated output documentation. The 'private:' and 'public:' tags must begin 125 | immediately following a ``/*`` comment marker. They may optionally include 126 | comments between the ``:`` and the ending ``*/`` marker. 127 | 128 | .. kernel-doc:: ./all-in-a-tumble.h 129 | :snippets: my_struct 130 | :language: c 131 | :linenos: 132 | 133 | Rendered example: :ref:`example.my_struct` 134 | 135 | All descriptions can be multi-line, except the short function description. For 136 | really longs ``structs``, you can also describe arguments inside the body of the 137 | ``struct``. There are two styles, single-line comments where both the opening 138 | ``/**`` and closing ``*/`` are on the same line, and multi-line comments where 139 | they are each on a line of their own, like all other kernel-doc comments: 140 | 141 | .. kernel-doc:: ./all-in-a-tumble.h 142 | :snippets: my_long_struct 143 | :language: c 144 | :linenos: 145 | 146 | Rendered example: :ref:`example.my_long_struct` 147 | 148 | 149 | .. _kernel-doc-syntax-enums-typedefs: 150 | 151 | enums, typedefs 152 | =============== 153 | 154 | To write documentation for enums and typedefs, you must write the name of the 155 | declaration; the ``enum`` or ``typedef`` must always precede the name. 156 | 157 | .. kernel-doc:: ./all-in-a-tumble.h 158 | :snippets: my_enum 159 | :language: c 160 | :linenos: 161 | 162 | Rendered example: :ref:`example.my_enum` 163 | 164 | .. kernel-doc:: ./all-in-a-tumble.h 165 | :snippets: my_typedef 166 | :language: c 167 | :linenos: 168 | 169 | Rendered example: :ref:`example.my_typedef` 170 | 171 | 172 | .. _kernel-doc-syntax-doc: 173 | 174 | documentation blocks 175 | ==================== 176 | 177 | To facilitate having source code and comments close together, you can include 178 | kernel-doc documentation blocks that are *free-form* comments instead of being 179 | kernel-doc for functions, structures, unions, enumerations, or typedefs. This 180 | could be used for something like a theory of operation for a driver or library 181 | code, for example. 182 | 183 | This is done by using a ``DOC:`` section keyword with a section title. A small 184 | example: 185 | 186 | .. kernel-doc:: ./all-in-a-tumble.h 187 | :snippets: theory-of-operation 188 | :language: c 189 | :linenos: 190 | 191 | Rendered example: :ref:`example.theory-of-operation` 192 | 193 | .. _kernel-doc-highlights: 194 | 195 | highlight pattern 196 | ================= 197 | 198 | All kernel-doc markup is processed as described above, all descriptive text is 199 | further processed, scanning for the following special patterns, which are 200 | highlighted appropriately. 201 | 202 | - ``user_function()`` : function 203 | - ``@a`` : name of a parameter 204 | - ``&struct my_struct`` : name of a structure (including the word struct) 205 | - ``&union my_union`` : name of a union 206 | - ``&my_struct->a`` or ``&my_struct.b`` - member of a struct or union. 207 | - ``&enum my_enum`` : name of a enum 208 | - ``&typedef my_typedef`` : name of a typedef 209 | - ``%CONST`` : name of a constant. 210 | - ``$ENVVAR`` : environmental variable 211 | 212 | The kernel-doc parser translates the pattern above to the corresponding reST_ 213 | markups (`sphinx domains`_):: 214 | 215 | - :c:func:`user_function` : function 216 | - ``a`` : name of a parameter 217 | - :c:type:`struct my_struct ` : name of a structure (including the word struct) 218 | - :c:type:`union my_union ` : name of a union 219 | - :c:type:`my_struct->a ` or :c:type:`my_struct.b ` - member of a struct or union. 220 | - :c:type:`enum my_enum ` : name of a enum 221 | - :c:type:`typedef my_typedef ` : name of a typedef 222 | - ``CONST`` : name of a constant. 223 | - ``$ENVVAR`` : environmental variable 224 | 225 | The `sphinx-doc`_ generator highlights these markups and tries to cross 226 | referencing to arbitrary locations (`sphinx cross references`_). The result of a 227 | cross reference depends on the context of the document which includes the 228 | kernel-doc comment. You don't have to use the *highlight* pattern, if you prefer 229 | *pure* reST, use the reST markup. 230 | 231 | Since the prefixes ``$...``, ``&...`` and ``@...`` are used to markup the 232 | highlight pattern, you have to escape them in other uses: ``\$...``, ``\&...`` 233 | and ``\@...``. 234 | 235 | .. hint:: 236 | 237 | The highlight pattern, are non regular reST markups. They are only available 238 | within kernel-doc comments, helping C developers to write short and compact 239 | documentation in source code comments. You can't use them in plain reST files 240 | (".rst"). If you are editing ".rst" files (e.g. files under ``Documentation``) 241 | please use the corresponding reST_ markups (`sphinx domains`_). 242 | 243 | 244 | .. _kernel-doc-syntax-snippets: 245 | 246 | Snippets 247 | ======== 248 | 249 | The kernel-doc Parser supports a comment-markup for snippets out of the source 250 | code. To start a region to snip insert:: 251 | 252 | /* parse-SNIP: */ 253 | 254 | The snippet region stops with a new snippet region or at the next:: 255 | 256 | /* parse-SNAP: */ 257 | 258 | Jump to :ref:`kernel-doc-snippets` to see an example. 259 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/kernel-doc-tests.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | 3 | .. _conf.py: http://www.sphinx-doc.org/en/stable/config.html 4 | 5 | .. _kernel-doc-tests: 6 | 7 | =============== 8 | kernel-doc Test 9 | =============== 10 | 11 | Wtihin this section you will find some :ref:`linuxdoc-howto` tests and examples 12 | for common use cases. The kernel-doc comments are taken from the source files 13 | :ref:`all-in-a-tumble.c-src` and :ref:`all-in-a-tumble.h-src`. 14 | 15 | .. _doc_sections: 16 | 17 | DOC sections 18 | ============ 19 | 20 | For a very simple example we use this DOC section from :ref:`all-in-a-tumble.h-src`: 21 | 22 | .. kernel-doc:: ./all-in-a-tumble.h 23 | :snippets: lorem 24 | 25 | To insert content with heading use: 26 | 27 | .. code-block:: rst 28 | 29 | .. kernel-doc:: ./all-in-a-tumble.h 30 | :doc: lorem ipsum 31 | :module: test 32 | 33 | With the module name ``test`` the title can be linked with: 34 | 35 | .. code-block:: rst 36 | 37 | Here is a link to DOC: :ref:`test.lorem-ipsum` 38 | 39 | Here is a link to DOC :ref:`test.lorem-ipsum` ... 40 | 41 | .. admonition:: DOC section with header 42 | :class: rst-example 43 | 44 | .. kernel-doc:: ./all-in-a-tumble.h 45 | :doc: lorem ipsum 46 | :module: test 47 | 48 | 49 | .. _opt_no-header: 50 | 51 | option ``:no-header:`` 52 | ---------------------- 53 | 54 | To insert just the content, without the header use :ref:`option :no-header: 55 | `: 56 | 57 | .. code-block:: rst 58 | 59 | .. kernel-doc:: ./all-in-a-tumble.h 60 | :doc: lorem ipsum 61 | :no-header: 62 | 63 | .. admonition:: DOC section without header 64 | :class: rst-example 65 | 66 | .. kernel-doc:: ./all-in-a-tumble.h 67 | :doc: lorem ipsum 68 | :no-header: 69 | 70 | 71 | .. _multiple_doc_sections: 72 | 73 | multiple DOC sections 74 | --------------------- 75 | 76 | Its always recommended to separate different DOC sections in different comments. 77 | Nevertheless, a few tests are to be carried out here with it. The DOC section 78 | tests are based on this comment: 79 | 80 | .. kernel-doc:: ./all-in-a-tumble.h 81 | :snippets: theory-of-operation 82 | 83 | ---- 84 | 85 | .. code-block:: rst 86 | 87 | .. kernel-doc:: ./all-in-a-tumble.h 88 | :doc: Theory of Operation 89 | :no-header: 90 | 91 | .. admonition:: DOC section 92 | :class: rst-example 93 | 94 | .. kernel-doc:: ./all-in-a-tumble.h 95 | :doc: Theory of Operation 96 | :no-header: 97 | 98 | ---- 99 | 100 | .. code-block:: rst 101 | 102 | .. kernel-doc:: ./all-in-a-tumble.h 103 | :doc: multiple DOC sections 104 | 105 | .. admonition:: DOC section 106 | :class: rst-example 107 | 108 | .. kernel-doc:: ./all-in-a-tumble.h 109 | :doc: multiple DOC sections 110 | 111 | 112 | .. _opt_man-sect: 113 | 114 | option ``:man-sect:`` 115 | ===================== 116 | 117 | .. _man_pages: http://www.sphinx-doc.org/en/stable/config.html#confval-man_pages 118 | 119 | In the :ref:`opt_export` example, we can add a ``:man-sect: 2`` option, to 120 | generate man pages with the :ref:`kernel-doc-man builder ` for all 121 | exported symbols. The usage is: 122 | 123 | .. code-block:: rst 124 | 125 | .. kernel-doc:: ./all-in-a-tumble.c 126 | :export: ./all-in-a-tumble.h 127 | :module: test 128 | :man-sect: 2 129 | 130 | In the conf.py_ file we set man_pages_ and :ref:`kernel_doc_mansect 131 | `:: 132 | 133 | kernel_doc_mansect = None 134 | man_pages = [ ] 135 | 136 | To place and gzip the manuals in ``dist/docs/man`` Folder see 137 | :ref:`kernel-doc-man_builder`. 138 | 139 | .. only:: builder_html 140 | 141 | You can include the man-page as a download item in your HTML like this 142 | (relative build path is needed): 143 | 144 | .. code-block:: rst 145 | 146 | :download:`user_function.2.gz <../../dist/docs/man/user_function.2.gz>` 147 | 148 | .. admonition:: download directive 149 | :class: rst-example 150 | 151 | :download:`user_function.2.gz <../../dist/docs/man/user_function.2.gz>` 152 | 153 | Or just set a link to the man page file (relative HTML URL is needed) 154 | 155 | .. code-block:: rst 156 | 157 | hyperlink to: `user_function.2.gz <../man/user_function.2.gz>`_ 158 | 159 | .. admonition:: link man folder ``/man`` 160 | :class: rst-example 161 | 162 | hyperlink to: `user_function.2.gz <../man/user_function.2.gz>`_ 163 | 164 | To view a (downloaded) man-page use:: 165 | 166 | $ man ~/Downloads/user_function.2.gz 167 | 168 | 169 | .. _exported_symbols: 170 | 171 | exported symbols 172 | ================ 173 | 174 | .. _opt_export: 175 | 176 | option ``:export:`` 177 | ------------------- 178 | 179 | In the :ref:`all-in-a-tumble.h-src` header file we export: 180 | 181 | .. kernel-doc:: ./all-in-a-tumble.h 182 | :snippets: EXPORT_SYMBOL 183 | 184 | The documentation of the exported symbols is in :ref:`all-in-a-tumble.c-src`. 185 | To gather exports from :ref:`all-in-a-tumble.h-src` and 186 | :ref:`all-in-a-tumble.c-src` and parses comments from 187 | :ref:`all-in-a-tumble.c-src` use :ref:`kernel-doc-options`: 188 | 189 | .. code-block:: rst 190 | 191 | .. kernel-doc:: ./all-in-a-tumble.c 192 | :export: ./all-in-a-tumble.h 193 | :module: test 194 | 195 | .. admonition:: exported symbols 196 | :class: rst-example 197 | 198 | .. kernel-doc:: ./all-in-a-tumble.c 199 | :export: ./all-in-a-tumble.h 200 | :module: test 201 | :man-sect: 2 202 | 203 | 204 | options ``:export:, :exp-method:, :exp-ids:`` 205 | --------------------------------------------- 206 | 207 | This test gathers function from :ref:`all-in-a-tumble.c-src` whose function 208 | attributes mark them as exported: 209 | 210 | .. kernel-doc:: ./all-in-a-tumble.c 211 | :snippets: user_sum-c 212 | 213 | and that are present in :ref:`all-in-a-tumble.h-src`: 214 | 215 | .. kernel-doc:: ./all-in-a-tumble.h 216 | :snippets: user_sum-h 217 | 218 | To insert the documentation use: 219 | 220 | .. code-block:: rst 221 | 222 | .. kernel-doc:: ./all-in-a-tumble.c 223 | :export: ./all-in-a-tumble.h 224 | :exp-method: attribute 225 | :exp-ids: API_EXPORTED 226 | :module: test.fnattrs 227 | 228 | The ``exp-method`` and ``exp-ids`` could be respectively omitted if 229 | ``kernel_doc_exp_method`` and ``kernel_doc_exp_ids`` are set in the sphinx 230 | configuration. 231 | 232 | .. admonition:: exported symbols 233 | :class: rst-example 234 | 235 | .. kernel-doc:: ./all-in-a-tumble.c 236 | :export: ./all-in-a-tumble.h 237 | :exp-method: attribute 238 | :exp-ids: API_EXPORTED 239 | :module: test.fnattrs 240 | 241 | .. _opt_internal: 242 | 243 | option ``:internal:`` 244 | --------------------- 245 | 246 | Include documentation of all documented definitions, **not** exported. This 247 | test gathers exports from :origin:`test_internals.h 248 | ` and :origin:`test_internals.c 249 | ` and parses comments from 250 | :origin:`test_internals.c `, from where 251 | only the *not exported* definitions are used in the reST output. 252 | 253 | .. attention:: 254 | 255 | The both examples below also demonstrate that it is not good to mix the 256 | export methods (``:exp-method: [macro|attribute]``) in one source 257 | ``test_internals.[hc]``. Only one methode can be used by the ``:internal:`` 258 | option to identfy a symbol to be exported. 259 | 260 | .. tabs:: 261 | 262 | .. group-tab:: exp-method is ``macro`` 263 | 264 | From :``test_internals.h``: 265 | 266 | .. kernel-doc:: ./test_internals.h 267 | :snippets: EXP_SYMB 268 | 269 | From ``test_internals.c``: 270 | 271 | .. kernel-doc:: ./test_internals.c 272 | :snippets: EXP_SYMB 273 | 274 | .. group-tab:: exp-method is ``attribute`` 275 | 276 | From ``test_internals.c``: 277 | 278 | .. kernel-doc:: ./test_internals.c 279 | :snippets: API_EXP 280 | 281 | From ``test_internals.h``: 282 | 283 | .. kernel-doc:: ./test_internals.h 284 | :snippets: API_EXP 285 | 286 | .. tabs:: 287 | 288 | .. group-tab:: exp-method is ``macro`` 289 | 290 | .. code-block:: rst 291 | 292 | .. kernel-doc:: ./test_internals.c 293 | :internal: ./test_internals.h 294 | :module: test_internals_A 295 | :exp-method: macro 296 | :exp-ids: EXP_SYMB 297 | :known-attrs: API_EXP 298 | 299 | Its not good to mix ``exp-method``, the ``know-attrs`` here is needed to 300 | avoid the Sphinx warning:: 301 | 302 | ./test_internals.c:24: WARNING: Error in declarator or parameters 303 | Invalid C declaration: Expected identifier in nested name, got keyword: int [error at 11] 304 | API_EXP int bar(int a, ...) 305 | -----------^ 306 | 307 | .. admonition:: internal symbols (when exp-method is ``macro``) 308 | :class: rst-example 309 | 310 | .. kernel-doc:: ./test_internals.c 311 | :internal: ./test_internals.h 312 | :module: test_internals_A 313 | :exp-method: macro 314 | :exp-ids: EXP_SYMB 315 | :known-attrs: API_EXP 316 | 317 | .. group-tab:: exp-method is ``attribute`` 318 | 319 | .. code-block:: rst 320 | 321 | .. kernel-doc:: ./test_internals.c 322 | :internal: ./test_internals.h 323 | :module: test_internals_B 324 | :exp-method: attribute 325 | :exp-ids: API_EXP 326 | 327 | .. admonition:: internal symbols (when exp-method is ``attribute``) 328 | :class: rst-example 329 | 330 | .. kernel-doc:: ./test_internals.c 331 | :internal: ./test_internals.h 332 | :module: test_internals_B 333 | :exp-method: attribute 334 | :exp-ids: API_EXP 335 | 336 | 337 | Missing exports 338 | --------------- 339 | 340 | In the next test, the ``:export: {file glob pattern}`` is used, but it does not 341 | match any file, or there are no exports in the matching files. Whatever, an 342 | empty list of exported symbols is treated as an error: 343 | 344 | .. code-block:: rst 345 | 346 | .. kernel-doc:: ./all-in-a-tumble.c 347 | :export: ./match_files_without_exports* 348 | 349 | .. admonition:: missing exports 350 | :class: rst-example 351 | 352 | .. kernel-doc:: ./all-in-a-tumble.c 353 | :export: ./match_files_without_exports* 354 | 355 | 356 | SYSCALL macro 357 | ============= 358 | 359 | In the Kernel's source is a macro: `SYSCALL_DEFINEn() 360 | `_. 361 | By example: 362 | 363 | 364 | .. kernel-doc:: ./all-in-a-tumble.c 365 | :snippets: test_SYSCALL 366 | 367 | .. code-block:: rst 368 | 369 | .. kernel-doc:: ./all-in-a-tumble.c 370 | :symbols: sys_tgkill 371 | 372 | .. admonition:: missing exports 373 | :class: rst-example 374 | 375 | .. kernel-doc:: ./all-in-a-tumble.c 376 | :symbols: sys_tgkill 377 | -------------------------------------------------------------------------------- /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/linuxdoc-howto/kfigure.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _kfigure: 5 | 6 | ================================== 7 | Scalable figure and image handling 8 | ================================== 9 | 10 | LinuxDoc brings the :py:mod:`linuxdoc.kfigure` Sphinx extension which implements 11 | scalable image handling. Scalable here means; *scalable* in sense of the build 12 | process. The build for image formats depends on image's source format and 13 | output's destination format. Different builder prefer different image formats, 14 | e.g. *latex* builder prefer PDF while *html* builder prefer SVG format for 15 | images. To get a pdf from a SVG input a third party converter is needed. 16 | Normally in absence of such a converter tool, the build process will break. 17 | From the authors POV it's annoying to care about the build process when handling 18 | with images, especially since he has no possibility to influence the build 19 | process on every build host out there. 20 | 21 | With the directives of :py:mod:`linuxdoc.kfigure`, if a third party converter is 22 | missed, the build process will spit out a message about and continues with a 23 | lower quality in the output. Even if the output is e.g. a raw SVG or DOT, in 24 | some use cases it might be a solution that fits. As we say, its *scalable*: If 25 | you are the operator of a build host, install the recommended tools and you will 26 | always get the best quality. For this the :py:mod:`linuxdoc.kfigure` implements 27 | a central :py:func:`convert_image ` function 28 | which is used by the directives: 29 | 30 | ``.. kernel-figure`` :ref:`[ref] ` 31 | Except remote URI and glob pattern, it's a full replacement for the 32 | :rst-directive:`figure` directive (:py:class:`KernelFigure 33 | `) 34 | 35 | ``.. kernel-image`` :ref:`[ref] ` 36 | A full replacement (except remote URI and glob pattern) for the 37 | :rst-directive:`image` directive (:py:class:`KernelImage 38 | `) 39 | 40 | ``.. kernel-render`` :ref:`[ref] ` 41 | Renders the block content by a converter tool (:py:class:`KernelRender 42 | `). Comparably to the :rst-directive:`figure` 43 | directive with the assumption that the content of the image is given in the 44 | block and not in an external image file. This directive is helpful for use 45 | cases where the image markup is editable and written by the author himself 46 | (e.g. a small DOT graph). 47 | 48 | Has all the options known from the figure directive, plus option caption. If 49 | caption has a value, a figure node with the caption is inserted. If not, a 50 | image node is inserted. 51 | 52 | Supported markups: 53 | 54 | - DOT_: render embedded Graphviz's DOC language (`Graphviz's dot`_) 55 | - SVG_: render embedded Scalable Vector Graphics 56 | - ... *developable* 57 | 58 | As already mentioned, the directives kernel-figure, kernel-image and 59 | kernel-render are based on one central function. In the current expansion stage 60 | :py:func:`convert_image ` uses the following 61 | tools (latex builder is used when generating PDF): 62 | 63 | - ``dot(1)`` `Graphviz's dot`_ command 64 | - ``convert(1)`` command from ImageMagick_ 65 | 66 | To summarize the build strategies: 67 | 68 | - DOT_ content, if `Graphviz's dot`_ command is not available 69 | 70 | - html builder: the DOT language is inserted as literal block. 71 | - latex builder: the DOT language is inserted as literal block. 72 | 73 | - SVG_ content 74 | 75 | - html builder: always insert SVG 76 | - latex builder: if ImageMagick_ is not available the raw SVG is inserted as 77 | literal-block. 78 | 79 | .. _kfigure_build_tools: 80 | 81 | .. admonition:: recommended build tools 82 | 83 | With the directives from :py:mod:`linuxdoc.kfigure` the build process is 84 | flexible. To get best results in the generated output format, install 85 | ImageMagick_ and Graphviz_. 86 | 87 | 88 | .. _kernel-figure: 89 | .. _kernel-image: 90 | 91 | kernel-figure & kernel-image 92 | ============================ 93 | 94 | If you want to add an image, you should use the ``kernel-figure`` and 95 | ``kernel-image`` directives. Except remote URI and glob pattern, they are full 96 | replacements for the :rst-directive:`figure` and :rst-directive:`image` 97 | directive. Here you will find a few recommendations for use, for a complete 98 | description see :rst-directive:`reST markup `. 99 | 100 | If you want to insert a image into your documentation, prefer a scalable 101 | vector-graphics_ format over a raster-graphics_ format. With scalable 102 | vector-graphics_ there is a chance, that the rendered output going to be best. 103 | SVG_ is a common and standardized vector-graphics_ format and there are many 104 | tools available to create and edit SVG_ images. That's why its recommended 105 | to use SVG_ in most use cases. 106 | 107 | In the literal block below, you will find a simple example on how to insert a 108 | SVG_ figure (image) with the ``kernel[-figure|image]`` directive, about 109 | rendering please note :ref:`build tools `: 110 | 111 | .. code-block:: rst 112 | 113 | .. _svg_image_example: 114 | 115 | .. kernel-figure:: svg_image.svg 116 | :alt: simple SVG image 117 | 118 | SVG figure example 119 | 120 | The first line in this example is only to show how an anchor is set and what 121 | a reference to it looks like :ref:`svg_image_example`. 122 | 123 | .. admonition:: kernel-figure SVG 124 | :class: rst-example 125 | 126 | .. _svg_image_example: 127 | 128 | .. kernel-figure:: svg_image.svg 129 | :alt: simple SVG image 130 | 131 | SVG figure example 132 | 133 | The first line in this example is only to show how an anchor is set and what 134 | a reference to it looks like :ref:`svg_image_example`. 135 | 136 | In addition to the :rst-directive:`figure` and :rst-directive:`image`, 137 | kernel-figure and kernel-image also support DOT_ formated files. A simple 138 | example is shown in figure :ref:`hello_dot_file`. 139 | 140 | .. code-block:: rst 141 | 142 | .. kernel-figure:: hello.dot 143 | :alt: hello world 144 | 145 | DOT's hello world example 146 | 147 | .. admonition:: kernel-figure DOT 148 | :class: rst-example 149 | 150 | .. _hello_dot_file: 151 | 152 | .. kernel-figure:: hello.dot 153 | :alt: hello world 154 | 155 | DOT's hello world example 156 | 157 | .. _kernel-render: 158 | 159 | kernel-render 160 | ============= 161 | 162 | Embed *render* markups (languages) like Graphviz's DOT_ or SVG_ are provided by 163 | the kernel-render directive. The kernel-render_ directive has all the options 164 | known from the :rst-directive:`image` directive (kernel-figure_), plus option 165 | ``caption``. If ``caption`` has a value, a :rst-directive:`figure` like node is 166 | inserted into the doctree_. If not, a :rst-directive:`image` like node is 167 | inserted. 168 | 169 | DOT markup 170 | ---------- 171 | 172 | A simple example of embedded DOT_ is shown in figure :ref:`hello_dot_render`: 173 | 174 | .. code-block:: rst 175 | 176 | .. _hello_dot_render: 177 | 178 | .. kernel-render:: DOT 179 | :alt: foobar digraph 180 | :caption: Embedded **DOT** (Graphviz) code 181 | 182 | digraph foo { 183 | "bar" -> "baz"; 184 | } 185 | 186 | A ``caption`` is needed, if you want to refer the figure: 187 | :ref:`hello_dot_render`. 188 | 189 | Please note :ref:`build tools `. If Graphviz_ is 190 | installed, you will see an vector image. If not, the raw markup is inserted as 191 | *literal-block*. 192 | 193 | .. admonition:: kernel-render DOT 194 | :class: rst-example 195 | 196 | .. _hello_dot_render: 197 | 198 | .. kernel-render:: DOT 199 | :alt: foobar digraph 200 | :caption: Embedded **DOT** (Graphviz) code 201 | 202 | digraph foo { 203 | "bar" -> "baz"; 204 | } 205 | 206 | A ``caption`` is needed, if you want to refer the figure: 207 | :ref:`hello_dot_render`. 208 | 209 | 210 | SVG markup 211 | ---------- 212 | 213 | A simple example of embedded SVG_ is shown in figure :ref:`hello_svg_render`: 214 | 215 | .. code-block:: rst 216 | 217 | .. _hello_svg_render: 218 | 219 | .. kernel-render:: SVG 220 | :caption: Embedded **SVG** markup 221 | :alt: so-nw-arrow 222 | 223 | 224 | 228 | 232 | 235 | 236 | 237 | .. admonition:: kernel-render SVG 238 | :class: rst-example 239 | 240 | .. _hello_svg_render: 241 | 242 | .. kernel-render:: SVG 243 | :caption: Embedded **SVG** markup 244 | :alt: so-nw-arrow 245 | 246 | 247 | 251 | 255 | 258 | 259 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/linuxdoc-howto/svg_image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/table-markup.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _`Emacs Table Mode`: https://www.emacswiki.org/emacs/TableMode 5 | .. _`Online Tables Generator`: http://www.tablesgenerator.com/text_tables 6 | .. _`OASIS XML Exchange Table Model`: https://www.oasis-open.org/specs/tm9901.html 7 | 8 | .. _xref_table_concerns: 9 | 10 | ============ 11 | About tables 12 | ============ 13 | 14 | .. note:: 15 | 16 | The :ref:`rest-flat-table` directive is the most **diff friendly** table 17 | markup, it is preferred in the Linux kernel tree. 18 | 19 | 20 | Intro 21 | ===== 22 | 23 | Internally, the docutils uses a representation according to the `OASIS XML 24 | Exchange Table Model`_ (same as DocBook). The *OASIS Table Model* gives a huge 25 | bandwidth of possibilities to form tables. This often seduce authors to force a 26 | specific layout. The misuse of tables in this manner is not recommended, it 27 | breaks the separation of *presentation from content* which most often ends in 28 | various problems in the range of output formats. Tables (and pre-formated text 29 | like source code listings) should be used advisedly. In a HTML viewer, the 30 | horizontal and vertical expansion is handled by a scrollbar. On print medias 31 | (paper / pdf) there is no scrollbar and automatically page-breaking a table or 32 | line-breaking a pre-formated text in the layout process ends mostly in unwanted 33 | results. 34 | 35 | .. hint:: 36 | 37 | Tables and pre-formated text in itself violate the separation of *presentation 38 | from content*, but we will never be able to entirely renounce them. Use them 39 | with care, if your content should be rendered well, in the wide variation of 40 | output formats. 41 | 42 | 43 | ASCII-art tables 44 | ================ 45 | 46 | ASCII-art tables might be comfortable for readers of the text-files, but they 47 | have huge disadvantages in the creation and modifying. First, they are hard to 48 | edit. Think about adding a row or a column to a ASCII-art table or adding a 49 | paragraph in a cell, it is a nightmare on big tables. Second the diff of 50 | modifying ASCII-art tables is not meaningful, e.g. widening a cell generates a 51 | diff in which also changes are included, which are only ascribable to the 52 | ASCII-art (see also :ref:`list-table-directives`). 53 | 54 | * `Emacs Table Mode`_ 55 | * `Online Tables Generator`_ 56 | 57 | 58 | Simple tables 59 | ------------- 60 | 61 | simple tables allow *colspan* but not *rowspan*: 62 | 63 | .. code-block:: none 64 | 65 | ====== ====== ====== 66 | Inputs Output 67 | ------------- ------ 68 | A B A or B 69 | ====== ====== ====== 70 | False 71 | -------------------- 72 | True 73 | -------------------- 74 | True False True 75 | ------ ------ ------ 76 | False True 77 | ====== ============= 78 | 79 | Rendered as: 80 | 81 | ====== ====== ====== 82 | Inputs Output 83 | ------------- ------ 84 | A B A or B 85 | ====== ====== ====== 86 | False 87 | -------------------- 88 | True 89 | -------------------- 90 | True False True 91 | ------ ------ ------ 92 | False True 93 | ====== ============= 94 | 95 | 96 | Grid tables 97 | ----------- 98 | 99 | grid tables allow colspan *colspan* and *rowspan*: 100 | 101 | .. code-block:: rst 102 | 103 | +------------+------------+-----------+ 104 | | Header 1 | Header 2 | Header 3 | 105 | +============+============+===========+ 106 | | body row 1 | column 2 | column 3 | 107 | +------------+------------+-----------+ 108 | | body row 2 | Cells may span columns.| 109 | +------------+------------+-----------+ 110 | | body row 3 | Cells may | - Cells | 111 | +------------+ span rows. | - contain | 112 | | body row 4 | | - blocks. | 113 | +------------+------------+-----------+ 114 | 115 | Rendered as: 116 | 117 | +------------+------------+-----------+ 118 | | Header 1 | Header 2 | Header 3 | 119 | +============+============+===========+ 120 | | body row 1 | column 2 | column 3 | 121 | +------------+------------+-----------+ 122 | | body row 2 | Cells may span columns.| 123 | +------------+------------+-----------+ 124 | | body row 3 | Cells may | - Cells | 125 | +------------+ span rows. | - contain | 126 | | body row 4 | | - blocks. | 127 | +------------+------------+-----------+ 128 | 129 | .. _list-table-directives: 130 | 131 | List table directives 132 | ===================== 133 | 134 | The *list table* formats are double stage list, compared to the ASCII-art they 135 | might not be as comfortable for readers of the text-files. Their advantage is, 136 | that they are easy to create/modify and that the diff of a modification is much 137 | more meaningful, because it is limited to the modified content. 138 | 139 | .. _rest-list-table: 140 | 141 | list-table 142 | ---------- 143 | 144 | The ``list-tables`` has no ability to *colspan* nor *rowspan*: 145 | 146 | .. code-block:: rst 147 | 148 | .. list-table:: list-table example 149 | :header-rows: 1 150 | :stub-columns: 1 151 | :class: my-class 152 | :name: my-list-table 153 | 154 | * - .. 155 | - head col 1 156 | - head col 2 157 | 158 | * - stub col row 1 159 | - column 160 | - column 161 | 162 | * - stub col row 2 163 | - column 164 | - column 165 | 166 | * - stub col row 3 167 | - column 168 | - column 169 | 170 | 171 | Rendered in :ref:`my-list-table`: 172 | 173 | .. list-table:: list-table example 174 | :header-rows: 1 175 | :stub-columns: 1 176 | :class: my-class 177 | :name: my-list-table 178 | 179 | * - .. 180 | - head col 1 181 | - head col 2 182 | 183 | * - stub col row 1 184 | - column 185 | - column 186 | 187 | * - stub col row 2 188 | - column 189 | - column 190 | 191 | * - stub col row 3 192 | - column 193 | - column 194 | 195 | .. _rest-flat-table: 196 | 197 | flat-table 198 | ---------- 199 | 200 | The ``flat-table`` (:py:class:`FlatTable`) is a double-stage list similar 201 | to the ``list-table`` with some additional features: 202 | 203 | * *column-span*: with the role ``cspan`` a cell can be extended through 204 | additional columns 205 | 206 | * *row-span*: with the role ``rspan`` a cell can be extended through 207 | additional rows 208 | 209 | * *auto-span* rightmost cell of a table row over the missing cells on the right 210 | side of that table-row. With Option ``:fill-cells:`` this behavior can 211 | changed from *auto span* to *auto fill*, which automatically inserts (empty) 212 | cells instead of spanning the last cell. 213 | 214 | options: 215 | :header-rows: [int] count of header rows 216 | :stub-columns: [int] count of stub columns 217 | :widths: [[int] [int] ... ] widths of columns 218 | :fill-cells: instead of auto-span missing cells, insert missing cells 219 | 220 | roles: 221 | :cspan: [int] additional columns (*morecols*) 222 | :rspan: [int] additional rows (*morerows*) 223 | 224 | The ``:rspan:`` and ``:cspan:`` are *special* reST-roles_. These directives 225 | are used in the :py:obj:`linuxdoc.rstFlatTable.ListTableBuilder` and 226 | :py:obj:`removed ` while 227 | the table is parsed. These reST-roles must not be in the translation: 228 | 229 | .. code-block:: po 230 | 231 | #: ../index.rst:21 232 | msgid ":rspan:`1` :cspan:`1` field 2.2 - 3.3" 233 | msgstr "test (fr) field 2.2 - 3.3" 234 | 235 | Most other reST-roles_ should be translated *as-is*: 236 | 237 | .. code-block:: po 238 | 239 | #: ../index.rst:48 240 | msgid ":math:`a^2 + b^2 = c^2`" 241 | msgstr "test (fr) :math:`a^2 + b^2 = c^2`" 242 | 243 | The example below shows how to use this markup. The first level of the staged 244 | list is the *table-row*. In the *table-row* there is only one markup allowed, 245 | the list of the cells in this *table-row*. Exception are *comments* ( ``..`` ) 246 | and *targets* (e.g. a ref to :ref:`row 2 of table's body `). 247 | 248 | .. code-block:: rst 249 | 250 | .. flat-table:: flat-table example 251 | :header-rows: 2 252 | :stub-columns: 1 253 | :widths: 1 1 1 1 2 254 | :class: my-class 255 | :name: my-flat-table 256 | 257 | * - :rspan:`1` head / stub 258 | - :cspan:`3` head 1.1-4 259 | 260 | * - head 2.1 261 | - head 2.2 262 | - head 2.3 263 | - head 2.4 264 | 265 | * .. row body 1 / this is a comment 266 | 267 | - row 1 268 | - :rspan:`2` cell 1-3.1 269 | - cell 1.2 270 | - cell 1.3 271 | - cell 1.4 272 | 273 | * .. Comments and targets are allowed on *table-row* stage. 274 | .. _`row body 2`: 275 | 276 | - row 2 277 | - cell 2.2 278 | - :rspan:`1` :cspan:`1` 279 | cell 2.3 with a span over 280 | 281 | * col 3-4 & 282 | * row 2-3 283 | 284 | * - row 3 285 | - cell 3.2 286 | 287 | * - row 4 288 | - cell 4.1 289 | - cell 4.2 290 | - cell 4.3 291 | - cell 4.4 292 | 293 | * - row 5 294 | - cell 5.1 with automatic span to rigth end 295 | 296 | * - row 6 297 | - cell 6.1 298 | - .. 299 | 300 | 301 | Rendered in :ref:`my-flat-table`: 302 | 303 | .. flat-table:: flat-table example 304 | :header-rows: 2 305 | :stub-columns: 1 306 | :widths: 1 1 1 1 2 307 | :class: my-class 308 | :name: my-flat-table 309 | 310 | * - :rspan:`1` head / stub 311 | - :cspan:`3` head 1.1-4 312 | 313 | * - head 2.1 314 | - head 2.2 315 | - head 2.3 316 | - head 2.4 317 | 318 | * .. row body 1 / this is a comment 319 | 320 | - row 1 321 | - :rspan:`2` cell 1-3.1 322 | - cell 1.2 323 | - cell 1.3 324 | - cell 1.4 325 | 326 | * .. Comments and targets are allowed on *table-row* stage. 327 | .. _`row body 2`: 328 | 329 | - row 2 330 | - cell 2.2 331 | - :rspan:`1` :cspan:`1` 332 | cell 2.3 with a span over 333 | 334 | * col 3-4 & 335 | * row 2-3 336 | 337 | * - row 3 338 | - cell 3.2 339 | 340 | * - row 4 341 | - cell 4.1 342 | - cell 4.2 343 | - cell 4.3 344 | - cell 4.4 345 | 346 | * - row 5 347 | - cell 5.1 with automatic span to rigth end 348 | 349 | * - row 6 350 | - cell 6.1 351 | - .. 352 | 353 | 354 | CSV table 355 | ========= 356 | 357 | CSV table might be the choice if you want to include CSV-data from a outstanding 358 | (build) process into your documentation. 359 | 360 | .. code-block:: rst 361 | 362 | .. csv-table:: csv-table example 363 | :header: , Header1, Header2 364 | :widths: 15, 10, 30 365 | :stub-columns: 1 366 | :file: csv_table.txt 367 | :class: my-class 368 | :name: my-csv-table 369 | 370 | Content of file ``csv_table.txt``: 371 | 372 | .. literalinclude:: csv_table.txt 373 | 374 | Rendered in :ref:`my-csv-table`: 375 | 376 | .. csv-table:: csv-table example 377 | :header: , Header1, Header2 378 | :widths: 15, 10, 30 379 | :stub-columns: 1 380 | :file: csv_table.txt 381 | :class: my-class 382 | :name: my-csv-table 383 | 384 | 385 | Nested Tables 386 | ============= 387 | 388 | Nested tables are ugly, don't use them! This part here is only to show what you 389 | should never do. They are ugly because they cause huge problems in many output 390 | formats and there is always no need for nested tables. 391 | 392 | .. code-block:: rst 393 | 394 | +-----------+----------------------------------------------------+ 395 | | W/NW cell | N/NE cell | 396 | | +-------------+--------------------------+-----------+ 397 | | | W/NW center | N/NE center | E/SE cell | 398 | | | +------------+-------------+ | 399 | | | | +--------+ | E/SE center | | 400 | | | | | nested | | | | 401 | | | | +--------+ | | | 402 | | | | | table | | | | 403 | | | | +--------+ | | | 404 | | +-------------+------------+ | | 405 | | | S/SE center | | | 406 | +-----------+--------------------------+-------------+ | 407 | | S/SW cell | | 408 | +----------------------------------------------------+-----------+ 409 | 410 | Rendered as: Not supported by all sphinx-builders, don't use nested tables!!! 411 | 412 | 413 | raw HTML tables 414 | =============== 415 | 416 | If HTML is the only format you want to render, you could use a raw-import of a 417 | HTML table markup. But be aware, this breaks the separation of *presentation from 418 | content*. HTML-Tables are only rendered within a HTML output. 419 | 420 | .. code-block:: html 421 | 422 |
423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 443 | 444 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 |
Owner Module/DriversGroupProperty NameTypeProperty ValuesObject attachedDescription/Restrictions
DRMGeneric"rotation"BITMASK{ 0, "rotate-0" }, { 1, "rotate-90" }, { 2, "rotate-180" }, { 3, 442 | "rotate-270" }, { 4, "reflect-x" }, { 5, "reflect-y" }CRTC, Planerotate-(degrees) rotates the image by the specified amount in 445 | degrees in counter clockwise direction. reflect-x and reflect-y 446 | reflects the image along the specified axis prior to rotation
Connector"EDID"BLOB | IMMUTABLE0ConnectorContains id of edid blob ptr object.
"DPMS"ENUM{ "On", "Standby", "Suspend", "Off" }ConnectorContains DPMS operation mode value.
"PATH"BLOB | IMMUTABLE0ConnectorContains topology path to a connector.
475 |
476 | 477 | 478 | 479 | .. raw:: html 480 | 481 |
482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 502 | 503 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 |
Owner Module/DriversGroupProperty NameTypeProperty ValuesObject attachedDescription/Restrictions
DRMGeneric"rotation"BITMASK{ 0, "rotate-0" }, { 1, "rotate-90" }, { 2, "rotate-180" }, { 3, 501 | "rotate-270" }, { 4, "reflect-x" }, { 5, "reflect-y" }CRTC, Planerotate-(degrees) rotates the image by the specified amount in 504 | degrees in counter clockwise direction. reflect-x and reflect-y 505 | reflects the image along the specified axis prior to rotation
Connector"EDID"BLOB | IMMUTABLE0ConnectorContains id of edid blob ptr object.
"DPMS"ENUM{ "On", "Standby", "Suspend", "Off" }ConnectorContains DPMS operation mode value.
"PATH"BLOB | IMMUTABLE0ConnectorContains topology path to a connector.
534 |
535 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /linuxdoc/autodoc.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """ 3 | autodoc 4 | ~~~~~~~ 5 | 6 | Implementation of the ``linuxdoc.autodoc`` 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.autodoc`` extracts the kernel-doc comments from the 12 | source code and uses them to create documentation of the source code in the reST 13 | markup:: 14 | 15 | $ linuxdoc.autodoc --help 16 | 17 | """ 18 | 19 | import argparse 20 | import multiprocessing 21 | import sys 22 | 23 | import six 24 | from fspath import FSPath 25 | 26 | from . import kernel_doc as kerneldoc 27 | from .kernel_doc import Container 28 | 29 | CMD = None 30 | 31 | MSG = lambda msg: sys.__stderr__.write("INFO : %s\n" % msg) 32 | ERR = lambda msg: sys.__stderr__.write("ERROR: %s\n" % msg) 33 | FATAL = lambda msg: sys.__stderr__.write("FATAL: %s\n" % msg) 34 | 35 | TEMPLATE_INDEX = """\ 36 | .. -*- coding: utf-8; mode: rst -*- 37 | 38 | ================================================================================ 39 | %(title)s 40 | ================================================================================ 41 | 42 | .. toctree:: 43 | :maxdepth: 1 44 | 45 | """ 46 | 47 | EPILOG = """This command uses the kernel-doc parser from the linuxdoc Sphinx 48 | extension, for details see: https://return42.github.io/linuxdoc/cmd-line.html""" 49 | 50 | DESCRIPTION = """The linuxdoc.autodoc tool can be used to generate documentation 51 | in the reST markup from the kernel-doc markup comments in the source files. 52 | This tool can be used to create an analogous document structure in reST markup 53 | from the folder structure of the source code. """ 54 | 55 | 56 | def main(): 57 | 58 | global CMD # pylint: disable=global-statement 59 | 60 | cli = get_cli() 61 | CMD = cli.parse_args() 62 | 63 | if not CMD.srctree.EXISTS: 64 | ERR("%s does not exists." % CMD.srctree) 65 | sys.exit(42) 66 | 67 | if not CMD.srctree.ISDIR: 68 | ERR("%s is not a folder." % CMD.srctree) 69 | sys.exit(42) 70 | 71 | if not CMD.force and CMD.doctree.EXISTS: 72 | ERR("%s is in the way, remove it first" % CMD.doctree) 73 | sys.exit(42) 74 | 75 | if CMD.markup == "kernel-doc" and CMD.rst_files: 76 | CMD.rst_files = CMD.rst_files.readFile().splitlines() 77 | else: 78 | CMD.rst_files = [] 79 | 80 | if CMD.threads > 1: 81 | # pylint: disable=consider-using-with 82 | pool = multiprocessing.Pool(CMD.threads) 83 | pool.map(autodoc_file, gather_filenames(CMD)) 84 | pool.close() 85 | pool.join() 86 | else: 87 | for fname in gather_filenames(CMD): 88 | autodoc_file(fname) 89 | 90 | insert_index_files(CMD.doctree) 91 | 92 | 93 | def get_cli(): 94 | 95 | cli = argparse.ArgumentParser( 96 | description=DESCRIPTION, 97 | epilog=EPILOG, 98 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 99 | ) 100 | cli.add_argument( 101 | "srctree", help="Folder of source code.", type=lambda x: FSPath(x).ABSPATH 102 | ) 103 | cli.add_argument( 104 | "doctree", 105 | help="Folder to place reST documentation.", 106 | type=lambda x: FSPath(x).ABSPATH, 107 | ) 108 | cli.add_argument( 109 | "--sloppy", 110 | action="store_true", 111 | help="Sloppy comment check, reports only severe errors.", 112 | ) 113 | cli.add_argument( 114 | "--force", action="store_true", help="Don't stop if doctree exists." 115 | ) 116 | cli.add_argument( 117 | "--threads", 118 | type=int, 119 | default=multiprocessing.cpu_count(), 120 | help="Use up to n threads.", 121 | ) 122 | cli.add_argument( 123 | "--markup", 124 | choices=["reST", "kernel-doc"], 125 | default="reST", 126 | help=( 127 | "Markup of the comments. Change this option only if you know what" 128 | " you do and make use of --rst-files if you also have some files in" 129 | " your source tree with reST markup. The markup of new comments must" 130 | " be reST!" 131 | ), 132 | ) 133 | cli.add_argument( 134 | "--rst-files", 135 | type=lambda x: FSPath(x).ABSPATH, 136 | help=( 137 | "File that list source files, which has comments in reST markup." 138 | " Use linuxdoc.grepdoc command to generate those file." 139 | ), 140 | ) 141 | 142 | return cli 143 | 144 | 145 | def gather_filenames(cmd): 146 | "yield .c & .h filenames" 147 | 148 | yield from cmd.srctree.reMatchFind(r"^.*\.[ch]$") 149 | 150 | 151 | def autodoc_file(fname): 152 | "generate documentation from fname" 153 | 154 | fname = fname.relpath(CMD.srctree) 155 | markup = CMD.markup 156 | 157 | if CMD.markup == "kernel-doc" and fname in CMD.rst_files: 158 | markup = "reST" 159 | 160 | opts = kerneldoc.ParseOptions( 161 | fname=fname, 162 | src_tree=CMD.srctree, 163 | verbose_warn=not (CMD.sloppy), 164 | use_all_docs=True, 165 | markup=markup, 166 | ) 167 | 168 | parser = kerneldoc.Parser(opts, kerneldoc.NullTranslator()) 169 | try: 170 | parser.parse() 171 | except Exception: # pylint: disable=broad-except 172 | FATAL("kernel-doc markup of %s seems buggy / can't parse" % opts.fname) 173 | return 174 | 175 | if not parser.ctx.dump_storage: 176 | # no kernel-doc comments found 177 | MSG("parsed: NONE comments: %s" % opts.fname) 178 | return 179 | 180 | MSG("parsed: %4d comments: %s" % (len(parser.ctx.dump_storage), opts.fname)) 181 | 182 | try: 183 | rst = six.StringIO() 184 | translator = kerneldoc.ReSTTranslator() 185 | opts.out = rst 186 | 187 | # First try to output reST, this might fail, because the kernel-doc 188 | # parser part is to tollerant ("bad lines", "function name and function 189 | # declaration are different", etc ...). 190 | parser.parse_dump_storage(translator=translator) 191 | 192 | out_file = CMD.doctree / fname.replace(".", "_") + ".rst" 193 | out_file.DIRNAME.makedirs() 194 | with out_file.openTextFile(mode="w") as out: 195 | out.write(rst.getvalue()) 196 | 197 | except Exception: # pylint: disable=broad-except 198 | FATAL("kernel-doc markup of %s seems buggy / can't parse" % opts.fname) 199 | return 200 | 201 | 202 | def insert_index_files(root_folder): 203 | "From root_folder traverse over subfolders and generate all index.rst files" 204 | 205 | for folder, dirnames, filenames in root_folder.walk(): 206 | ctx = Container(title=folder.FILENAME) 207 | dirnames.sort() 208 | filenames.sort() 209 | index_file = folder / "index.rst" 210 | MSG("create index: %s" % index_file) 211 | with index_file.openTextFile(mode="w") as index: 212 | index.write(TEMPLATE_INDEX % ctx) 213 | for _d in dirnames: 214 | index.write(" %s/index\n" % _d.FILENAME) 215 | for _f in filenames: 216 | if _f.FILENAME == "index": 217 | continue 218 | index.write(" %s\n" % _f.FILENAME) 219 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /linuxdoc/kernel_include.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | """ 4 | kernel-include 5 | ~~~~~~~~~~~~~~ 6 | 7 | Implementation of the ``kernel-include`` reST-directive. 8 | 9 | :copyright: Copyright (C) 2018 Markus Heiser 10 | :license: AGPL-3.0-or-later; see LICENSE for details. 11 | 12 | For user documentation see :ref:`kernel-include-directive`. 13 | """ 14 | 15 | # ============================================================================== 16 | # imports 17 | # ============================================================================== 18 | 19 | import os.path 20 | 21 | from docutils import io, nodes, statemachine 22 | from docutils.parsers.rst import directives 23 | from docutils.parsers.rst.directives.body import CodeBlock, NumberLines 24 | from docutils.parsers.rst.directives.misc import Include 25 | from docutils.utils.error_reporting import ErrorString, SafeString 26 | 27 | __version__ = "1.0" 28 | 29 | 30 | # ============================================================================== 31 | def setup(app): # pylint: disable=missing-docstring 32 | # ============================================================================== 33 | 34 | app.add_directive("kernel-include", KernelInclude) 35 | return dict(version=__version__, parallel_read_safe=True, parallel_write_safe=True) 36 | 37 | 38 | # ============================================================================== 39 | class KernelInclude(Include): 40 | # ============================================================================== 41 | 42 | """KernelInclude (``kernel-include``) directive""" 43 | 44 | def run(self): 45 | path = os.path.realpath(os.path.expandvars(self.arguments[0])) 46 | 47 | # to get a bit security back, prohibit /etc: 48 | if path.startswith(os.sep + "etc"): 49 | raise self.severe( 50 | 'Problems with "%s" directive, prohibited path: %s' % (self.name, path) 51 | ) 52 | 53 | self.arguments[0] = path 54 | 55 | # return super(KernelInclude, self).run() # won't work, see HINTs in _run() 56 | return self._run() 57 | 58 | def _run(self): # pylint: disable=R 59 | """Include a file as part of the content of this reST file.""" 60 | 61 | # HINT: I had to copy&paste the whole Include.run method. I'am not happy 62 | # with this, but due to security reasons, the Include.run method does 63 | # not allow absolute or relative pathnames pointing to locations *above* 64 | # the filesystem tree where the reST document is placed. 65 | 66 | if not self.state.document.settings.file_insertion_enabled: 67 | raise self.warning('"%s" directive disabled.' % self.name) 68 | source = self.state_machine.input_lines.source( 69 | self.lineno - self.state_machine.input_offset - 1 70 | ) 71 | source_dir = os.path.dirname(os.path.abspath(source)) 72 | path = directives.path(self.arguments[0]) 73 | if path.startswith("<") and path.endswith(">"): 74 | path = os.path.join(self.standard_include_path, path[1:-1]) 75 | path = os.path.normpath(os.path.join(source_dir, path)) 76 | 77 | encoding = self.options.get( 78 | "encoding", self.state.document.settings.input_encoding 79 | ) 80 | e_handler = self.state.document.settings.input_encoding_error_handler 81 | tab_width = self.options.get( 82 | "tab-width", self.state.document.settings.tab_width 83 | ) 84 | try: 85 | self.state.document.settings.record_dependencies.add(path) 86 | include_file = io.FileInput( 87 | source_path=path, encoding=encoding, error_handler=e_handler 88 | ) 89 | except UnicodeEncodeError: 90 | # pylint: disable=raise-missing-from 91 | raise self.severe( 92 | 'Problems with "%s" directive path:\n' 93 | 'Cannot encode input file path "%s" ' 94 | "(wrong locale?)." % (self.name, SafeString(path)) 95 | ) 96 | except IOError as error: 97 | raise self.severe( 98 | 'Problems with "%s" directive path:\n%s.' 99 | % (self.name, ErrorString(error)) 100 | ) 101 | startline = self.options.get("start-line", None) 102 | endline = self.options.get("end-line", None) 103 | try: 104 | rawtext = "" 105 | if startline or (endline is not None): 106 | lines = include_file.readlines() 107 | rawtext = "".join(lines[startline:endline]) 108 | else: 109 | rawtext = include_file.read() 110 | except UnicodeError as error: 111 | raise self.severe( 112 | 'Problem with "%s" directive:\n%s' % (self.name, ErrorString(error)) 113 | ) 114 | # start-after/end-before: no restrictions on newlines in match-text, 115 | # and no restrictions on matching inside lines vs. line boundaries 116 | after_text = self.options.get("start-after", None) 117 | if after_text: 118 | # skip content in rawtext before *and incl.* a matching text 119 | after_index = rawtext.find(after_text) 120 | if after_index < 0: 121 | raise self.severe( 122 | 'Problem with "start-after" option of "%s" ' 123 | "directive:\nText not found." % self.name 124 | ) 125 | rawtext = rawtext[after_index + len(after_text) :] 126 | before_text = self.options.get("end-before", None) 127 | if before_text: 128 | # skip content in rawtext after *and incl.* a matching text 129 | before_index = rawtext.find(before_text) 130 | if before_index < 0: 131 | raise self.severe( 132 | 'Problem with "end-before" option of "%s" ' 133 | "directive:\nText not found." % self.name 134 | ) 135 | rawtext = rawtext[:before_index] 136 | 137 | include_lines = statemachine.string2lines( 138 | rawtext, tab_width, convert_whitespace=True 139 | ) 140 | if "literal" in self.options: 141 | # Convert tabs to spaces, if `tab_width` is positive. 142 | if tab_width >= 0: 143 | text = rawtext.expandtabs(tab_width) 144 | else: 145 | text = rawtext 146 | literal_block = nodes.literal_block( 147 | rawtext, source=path, classes=self.options.get("class", []) 148 | ) 149 | literal_block.line = 1 150 | self.add_name(literal_block) 151 | if "number-lines" in self.options: 152 | try: 153 | startline = int(self.options["number-lines"] or 1) 154 | except ValueError as exc: 155 | raise self.error( 156 | ":number-lines: with non-integer start value" 157 | ) from exc 158 | endline = startline + len(include_lines) 159 | if text.endswith("\n"): 160 | text = text[:-1] 161 | tokens = NumberLines([([], text)], startline, endline) 162 | for classes, value in tokens: 163 | if classes: 164 | literal_block += nodes.inline(value, value, classes=classes) 165 | else: 166 | literal_block += nodes.Text(value, value) 167 | else: 168 | literal_block += nodes.Text(text, text) 169 | return [literal_block] 170 | if "code" in self.options: 171 | self.options["source"] = path 172 | codeblock = CodeBlock( 173 | self.name, 174 | [self.options.pop("code")], # arguments 175 | self.options, 176 | include_lines, # content 177 | self.lineno, 178 | self.content_offset, 179 | self.block_text, 180 | self.state, 181 | self.state_machine, 182 | ) 183 | return codeblock.run() 184 | self.state_machine.insert_input(include_lines, path) 185 | return [] 186 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /linuxdoc/manKernelDoc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | # pylint: disable=missing-docstring, invalid-name, unnecessary-pass 4 | """\ 5 | kernel-doc-man 6 | ~~~~~~~~~~~~~~ 7 | 8 | Implementation of the ``kernel-doc-man`` builder. 9 | 10 | User documentation see :ref:`man-pages`. 11 | """ 12 | 13 | # ============================================================================== 14 | # imports 15 | # ============================================================================== 16 | 17 | import collections 18 | import re 19 | from os import path 20 | 21 | from docutils import nodes 22 | from docutils.frontend import OptionParser 23 | from docutils.io import FileOutput 24 | from docutils.parsers.rst import Directive 25 | from docutils.transforms import Transform 26 | from docutils.utils import new_document 27 | from sphinx import addnodes 28 | from sphinx.builders.manpage import ManualPageBuilder 29 | from sphinx.util import logging 30 | from sphinx.util.console import bold, darkgreen # pylint: disable=no-name-in-module 31 | from sphinx.util.nodes import inline_all_toctrees 32 | from sphinx.writers.manpage import ManualPageWriter 33 | 34 | from .kernel_doc import Container 35 | 36 | logger = logging.getLogger(__name__) 37 | 38 | # ============================================================================== 39 | # common globals 40 | # ============================================================================== 41 | 42 | DEFAULT_MAN_SECT = 9 43 | 44 | # The version numbering follows numbering of the specification 45 | # (Documentation/books/kernel-doc-HOWTO). 46 | __version__ = "1.0" 47 | 48 | 49 | # ============================================================================== 50 | def setup(app): 51 | # ============================================================================== 52 | 53 | app.add_builder(KernelDocManBuilder) 54 | app.add_directive("kernel-doc-man", KernelDocMan) 55 | app.add_node( 56 | kernel_doc_man, 57 | html=(skip_kernel_doc_man, None), 58 | latex=(skip_kernel_doc_man, None), 59 | texinfo=(skip_kernel_doc_man, None), 60 | text=(skip_kernel_doc_man, None), 61 | man=(skip_kernel_doc_man, None), 62 | ) 63 | 64 | return dict(version=__version__, parallel_read_safe=True, parallel_write_safe=True) 65 | 66 | 67 | # ============================================================================== 68 | class kernel_doc_man(nodes.Invisible, nodes.Element): # pylint: disable=invalid-name 69 | # ============================================================================== 70 | """Node to mark a section as *manpage*""" 71 | 72 | 73 | def skip_kernel_doc_man(self, node): # pylint: disable=unused-argument 74 | raise nodes.SkipNode 75 | 76 | 77 | # ============================================================================== 78 | class KernelDocMan(Directive): 79 | # ============================================================================== 80 | 81 | required_arguments = 1 82 | optional_arguments = 0 83 | 84 | def run(self): 85 | man_node = kernel_doc_man() 86 | man_node["manpage"] = self.arguments[0] 87 | return [man_node] 88 | 89 | 90 | # ============================================================================== 91 | class Section2Manpage(Transform): 92 | # ============================================================================== 93 | """Transforms a *section* tree into an *manpage* tree. 94 | 95 | The structural layout of a man-page differs from the one produced, by the 96 | kernel-doc parser. The kernel-doc parser produce reST which fits to *normal* 97 | documentation, e.g. the declaration of a function in reST is like. 98 | 99 | .. code-block:: rst 100 | 101 | user_function 102 | ============= 103 | 104 | .. c:function:: int user_function(int a) 105 | 106 | The *purpose* description. 107 | 108 | :param int a: 109 | Parameter a description 110 | 111 | Description 112 | =========== 113 | 114 | lorem ipsum .. 115 | 116 | Return 117 | ====== 118 | 119 | Returns first argument 120 | 121 | On the other side, in man-pages it is common (see ``man man-pages``) to 122 | print the *purpose* line in the "NAME" section, function's prototype in the 123 | "SYNOPSIS" section and the parameter description in the "OPTIONS" section:: 124 | 125 | NAME 126 | user_function -- The *purpose* description. 127 | 128 | SYNOPSIS 129 | int user_function(int a) 130 | 131 | OPTIONS 132 | a 133 | 134 | DESCRIPTION 135 | lorem ipsum 136 | 137 | RETURN VALUE 138 | Returns first argument 139 | 140 | """ 141 | # The common section order is: 142 | manTitles = [ 143 | (re.compile(r"^SYNOPSIS|^DEFINITION", flags=re.I), "SYNOPSIS"), 144 | (re.compile(r"^CONFIG", flags=re.I), "CONFIGURATION"), 145 | (re.compile(r"^DESCR", flags=re.I), "DESCRIPTION"), 146 | (re.compile(r"^OPTION", flags=re.I), "OPTIONS"), 147 | (re.compile(r"^EXIT", flags=re.I), "EXIT STATUS"), 148 | (re.compile(r"^RETURN", flags=re.I), "RETURN VALUE"), 149 | (re.compile(r"^ERROR", flags=re.I), "ERRORS"), 150 | (re.compile(r"^ENVIRON", flags=re.I), "ENVIRONMENT"), 151 | (re.compile(r"^FILE", flags=re.I), "FILES"), 152 | (re.compile(r"^VER", flags=re.I), "VERSIONS"), 153 | (re.compile(r"^ATTR", flags=re.I), "ATTRIBUTES"), 154 | (re.compile(r"^CONFOR", flags=re.I), "CONFORMING TO"), 155 | (re.compile(r"^NOTE", flags=re.I), "NOTES"), 156 | (re.compile(r"^BUG", flags=re.I), "BUGS"), 157 | (re.compile(r"^EXAMPLE", flags=re.I), "EXAMPLE"), 158 | (re.compile(r"^SEE", flags=re.I), "SEE ALSO"), 159 | ] 160 | 161 | manTitleOrder = [t for r, t in manTitles] 162 | 163 | @classmethod 164 | def sec2man_get_first_child(cls, subtree, *classes): 165 | for _c in classes: 166 | if subtree is None: 167 | break 168 | idx = subtree.first_child_matching_class(_c) 169 | if idx is None: 170 | subtree = None 171 | break 172 | subtree = subtree[idx] 173 | return subtree 174 | 175 | def strip_man_info(self): 176 | section = self.document[0] 177 | man_info = Container(authors=[]) 178 | man_node = self.sec2man_get_first_child(section, kernel_doc_man) 179 | name, sect = (man_node["manpage"].split(".", -1) + [DEFAULT_MAN_SECT])[:2] 180 | man_info["manpage"] = name 181 | man_info["mansect"] = sect 182 | 183 | # strip field list 184 | field_list = self.sec2man_get_first_child(section, nodes.field_list) 185 | if field_list: 186 | field_list.parent.remove(field_list) 187 | for field in field_list: 188 | name = field[0].astext().lower() 189 | value = field[1].astext() 190 | man_info[name] = man_info.get(name, []) + [ 191 | value, 192 | ] 193 | 194 | # normalize authors 195 | for auth, adr in zip( 196 | man_info.get("author", []), man_info.get("address", []) 197 | ): 198 | man_info["authors"].append("%s <%s>" % (auth, adr)) 199 | 200 | # strip *purpose* 201 | desc_content = self.sec2man_get_first_child( 202 | section, addnodes.desc, addnodes.desc_content 203 | ) 204 | if not desc_content or not desc_content: 205 | # missing initial short description in kernel-doc comment 206 | man_info.subtitle = "" 207 | else: 208 | man_info.subtitle = desc_content[0].astext() 209 | del desc_content[0] 210 | 211 | # remove section title 212 | old_title = self.sec2man_get_first_child(section, nodes.title) 213 | old_title.parent.remove(old_title) 214 | 215 | # gather type of the declaration 216 | decl_type = self.sec2man_get_first_child( 217 | section, addnodes.desc, addnodes.desc_signature, addnodes.desc_type 218 | ) 219 | if decl_type is not None: 220 | decl_type = decl_type.astext().strip() 221 | man_info.decl_type = decl_type 222 | 223 | # complete infos 224 | man_info.title = man_info["manpage"] 225 | man_info.section = man_info["mansect"] 226 | 227 | return man_info 228 | 229 | def isolate_sections(self, sec_by_title): 230 | section = self.document[0] 231 | while True: 232 | sect = self.sec2man_get_first_child(section, nodes.section) 233 | if not sect: 234 | break 235 | sec_parent = sect.parent 236 | target_idx = sect.parent.index(sect) - 1 237 | sect.parent.remove(sect) 238 | if isinstance(sec_parent[target_idx], nodes.target): 239 | # drop target / is useless in man-pages 240 | del sec_parent[target_idx] 241 | title = sect[0].astext().upper() 242 | for r, man_title in self.manTitles: # pylint: disable=invalid-name 243 | if r.search(title): 244 | title = man_title 245 | sect[0].replace_self(nodes.title(text=title)) 246 | break 247 | # we dont know if there are sections with the same title 248 | sec_by_title[title] = sec_by_title.get(title, []) + [sect] 249 | 250 | return sec_by_title 251 | 252 | def isolate_synopsis(self, sec_by_title): 253 | synopsis = None 254 | c_desc = self.sec2man_get_first_child(self.document[0], addnodes.desc) 255 | if c_desc is not None: 256 | c_desc.parent.remove(c_desc) 257 | synopsis = nodes.section() 258 | synopsis += nodes.title(text="synopsis") 259 | synopsis += c_desc 260 | sec_by_title["SYNOPSIS"] = sec_by_title.get("SYNOPSIS", []) + [synopsis] 261 | return sec_by_title 262 | 263 | def apply(self, **kwargs): 264 | self.document.man_info = self.strip_man_info() 265 | sec_by_title = collections.OrderedDict() 266 | 267 | self.isolate_sections(sec_by_title) 268 | # On struct, enum, union, typedef, the SYNOPSIS is taken from the 269 | # DEFINITION section. 270 | if self.document.man_info.decl_type not in [ 271 | "struct", 272 | "enum", 273 | "union", 274 | "typedef", 275 | ]: 276 | self.isolate_synopsis(sec_by_title) 277 | 278 | for sec_name in self.manTitleOrder: 279 | sec_list = sec_by_title.pop(sec_name, []) 280 | self.document[0] += sec_list 281 | 282 | for sec_list in sec_by_title.values(): 283 | self.document[0] += sec_list 284 | 285 | 286 | # ============================================================================== 287 | class KernelDocManBuilder(ManualPageBuilder): 288 | # ============================================================================== 289 | 290 | """ 291 | Builds groff output in manual page format. 292 | """ 293 | name = "kernel-doc-man" 294 | format = "man" 295 | supported_image_types = [] 296 | 297 | def init(self): 298 | pass 299 | 300 | def is_manpage(self, node): 301 | if isinstance(node, nodes.section): 302 | return bool( 303 | Section2Manpage.sec2man_get_first_child(node, kernel_doc_man) 304 | is not None 305 | ) 306 | return False 307 | 308 | def prepare_writing(self, docnames): 309 | """A place where you can add logic before :meth:`write_doc` is run""" 310 | pass 311 | 312 | def write_doc(self, docname, doctree): 313 | """Where you actually write something to the filesystem.""" 314 | pass 315 | 316 | def get_partial_document(self, children): 317 | doc_tree = new_document("") 318 | doc_tree += children 319 | return doc_tree 320 | 321 | def write(self, *ignored): # pylint: disable=overridden-final-method 322 | if self.config.man_pages: 323 | # build manpages from config.man_pages as usual 324 | ManualPageBuilder.write(self, *ignored) 325 | 326 | logger.info( 327 | bold("scan master tree for kernel-doc man-pages ... ") + darkgreen("{"), 328 | nonl=True, 329 | ) 330 | 331 | master_tree = self.env.get_doctree(self.config.master_doc) 332 | master_tree = inline_all_toctrees( 333 | self, 334 | set(), 335 | self.config.master_doc, 336 | master_tree, 337 | darkgreen, 338 | [self.config.master_doc], 339 | ) 340 | logger.info(darkgreen("}")) 341 | man_nodes = master_tree.traverse(condition=self.is_manpage) 342 | if not man_nodes and not self.config.man_pages: 343 | logger.warning( 344 | 'no "man_pages" config value nor manual section found; no manual pages ' 345 | "will be written" 346 | ) 347 | return 348 | 349 | logger.info(bold("START writing man pages ... "), nonl=True) 350 | 351 | for man_parent in man_nodes: 352 | 353 | doc_tree = self.get_partial_document(man_parent) 354 | Section2Manpage(doc_tree).apply() 355 | 356 | if not doc_tree.man_info["authors"] and self.config.author: 357 | doc_tree.man_info["authors"].append(self.config.author) 358 | 359 | doc_writer = ManualPageWriter(self) 360 | doc_settings = OptionParser( 361 | defaults=self.env.settings, 362 | components=(doc_writer,), 363 | read_config_files=True, 364 | ).get_default_values() 365 | 366 | doc_settings.__dict__.update(doc_tree.man_info) 367 | doc_tree.settings = doc_settings 368 | targetname = "%s.%s" % (doc_tree.man_info.title, doc_tree.man_info.section) 369 | if doc_tree.man_info.decl_type in ["struct", "enum", "union", "typedef"]: 370 | targetname = "%s_%s" % (doc_tree.man_info.decl_type, targetname) 371 | 372 | destination = FileOutput( 373 | destination_path=path.join(self.outdir, targetname), encoding="utf-8" 374 | ) 375 | 376 | logger.info(darkgreen(targetname) + " ", nonl=True) 377 | self.env.resolve_references(doc_tree, doc_tree.man_info.manpage, self) 378 | 379 | # remove pending_xref nodes 380 | for pendingnode in doc_tree.traverse(addnodes.pending_xref): 381 | pendingnode.replace_self(pendingnode.children) 382 | doc_writer.write(doc_tree, destination) 383 | logger.info("END writing man pages.") 384 | 385 | def finish(self): 386 | pass 387 | -------------------------------------------------------------------------------- /linuxdoc/rest.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """ 3 | rest 4 | ~~~~ 5 | 6 | Implementation of the ``linuxdoc.rest`` command. 7 | 8 | :copyright: Copyright (C) 2023 Markus Heiser 9 | :license: AGPL-3.0-or-later; see LICENSE for details. 10 | 11 | The ``linuxdoc.rest`` command parses kernel-doc comments from source code and 12 | print the reST to stdout:: 13 | 14 | $ linuxdoc.rest --help 15 | 16 | """ 17 | 18 | import argparse 19 | 20 | from fspath import FSPath 21 | 22 | from . import kernel_doc 23 | 24 | CMD = None 25 | 26 | EPILOG = """This command uses the kernel-doc parser from the linuxdoc Sphinx 27 | extension, for details see: https://return42.github.io/linuxdoc/cmd-line.html""" 28 | 29 | DESCRIPTION = """ The linuxdoc.rest command converts the kernel-doc markup 30 | comments in the source code files to reST markup. """ 31 | 32 | 33 | def main(): 34 | 35 | global CMD # pylint: disable=global-statement 36 | 37 | cli = get_cli() 38 | CMD = cli.parse_args() 39 | 40 | kernel_doc.VERBOSE = CMD.verbose 41 | kernel_doc.DEBUG = CMD.debug 42 | 43 | if CMD.quiet: 44 | kernel_doc.STREAM.log_out = kernel_doc.DevNull 45 | 46 | ret_val = 0 47 | 48 | src_tree = FSPath.getCWD() 49 | for fname in CMD.files: 50 | fname = FSPath(fname) 51 | translator = kernel_doc.ReSTTranslator() 52 | opts = kernel_doc.ParseOptions( 53 | fname=fname.relpath(src_tree), 54 | src_tree=src_tree, 55 | id_prefix=CMD.id_prefix, 56 | skip_preamble=CMD.skip_preamble, 57 | skip_epilog=CMD.skip_epilog, 58 | out=kernel_doc.STREAM.appl_out, 59 | markup=CMD.markup, 60 | verbose_warn=not (CMD.sloppy), 61 | exp_method=CMD.symbols_exported_method, 62 | exp_ids=CMD.symbols_exported_identifiers, 63 | known_attrs=CMD.known_attrs, 64 | ) 65 | opts.set_defaults() 66 | 67 | if CMD.list_exports or CMD.list_internals: 68 | translator = kernel_doc.ListTranslator(CMD.list_exports, CMD.list_internals) 69 | opts.gather_context = True 70 | 71 | elif CMD.use_names: 72 | opts.use_names = CMD.use_names 73 | 74 | elif CMD.exported or CMD.internal: 75 | # gather exported symbols ... 76 | src = kernel_doc.readFile(opts.fname) 77 | ctx = kernel_doc.ParserContext() 78 | kernel_doc.Parser.gather_context(src, ctx, opts) 79 | 80 | opts.error_missing = False 81 | opts.use_names = ctx.exported_symbols 82 | opts.skip_names = [] 83 | 84 | if CMD.internal: 85 | opts.use_names = [] 86 | opts.skip_names = ctx.exported_symbols 87 | else: 88 | # if non section is choosen by use-name, internal or exclude, then 89 | # use all DOC: sections 90 | opts.use_all_docs = True 91 | 92 | parser = kernel_doc.Parser(opts, translator) 93 | parser.parse() 94 | parser.close() 95 | if parser.errors: 96 | ret_val = 1 97 | 98 | return ret_val 99 | 100 | 101 | def get_cli(): 102 | 103 | cli = argparse.ArgumentParser( 104 | description=DESCRIPTION, 105 | epilog=EPILOG, 106 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 107 | ) 108 | cli.add_argument("files", nargs="+", help="source file(s) to parse.") 109 | cli.add_argument( 110 | "--id-prefix", 111 | default="", 112 | help=( 113 | "A prefix for automatic generated IDs. The IDs are automaticly" 114 | " gernerated based on the declaration and/or section names. The" 115 | " prefix is also used as namespace in Sphinx's C-domain" 116 | ), 117 | ) 118 | cli.add_argument( 119 | "--verbose", 120 | "-v", 121 | action="store_true", 122 | help="verbose output with log messages to stderr", 123 | ) 124 | cli.add_argument( 125 | "--sloppy", 126 | action="store_true", 127 | help="Sloppy linting, reports only severe errors.", 128 | ) 129 | cli.add_argument("--debug", action="store_true", help="debug messages to stderr") 130 | cli.add_argument("--quiet", "-q", action="store_true", help="no messages to stderr") 131 | cli.add_argument( 132 | "--skip-preamble", action="store_true", help="skip preamble in the output" 133 | ) 134 | cli.add_argument( 135 | "--skip-epilog", action="store_true", help="skip epilog in the output" 136 | ) 137 | cli.add_argument( 138 | "--list-internals", 139 | choices=kernel_doc.Parser.DOC_TYPES + ["all"], 140 | nargs="+", 141 | help="List symbols, titles or whatever is documented, but *not* exported.", 142 | ) 143 | cli.add_argument( 144 | "--list-exports", action="store_true", help="List all exported symbols." 145 | ) 146 | cli.add_argument( 147 | "--use-names", 148 | nargs="+", 149 | help=("Print reST markup of functions, structs or whatever title/object"), 150 | ) 151 | cli.add_argument( 152 | "--exported", 153 | action="store_true", 154 | help="Print documentation of all exported symbols.", 155 | ) 156 | cli.add_argument( 157 | "--internal", 158 | action="store_true", 159 | help=( 160 | "Print documentation of all symbols that are documented," 161 | " but not exported" 162 | ), 163 | ) 164 | cli.add_argument( 165 | "--markup", 166 | choices=["reST", "kernel-doc"], 167 | default="reST", 168 | help=( 169 | "Markup of the comments. Change this option only if you know" 170 | " what you do. New comments must be marked up with reST!" 171 | ), 172 | ) 173 | cli.add_argument( 174 | "--symbols-exported-method", 175 | default=kernel_doc.DEFAULT_EXP_METHOD, 176 | help=( 177 | "Indicate the way by which an exported symbol" 178 | " is exported. Must be either 'macro' or 'attribute'." 179 | ), 180 | ) 181 | cli.add_argument( 182 | "--symbols-exported-identifiers", 183 | nargs="+", 184 | default=kernel_doc.DEFAULT_EXP_IDS, 185 | help="Identifiers list that specifies an exported symbol.", 186 | ) 187 | cli.add_argument( 188 | "--known-attrs", 189 | default=[], 190 | nargs="+", 191 | help=( 192 | "Provides a list of known attributes that has to be" 193 | " hidden when displaying function prototypes" 194 | ), 195 | ) 196 | 197 | return cli 198 | -------------------------------------------------------------------------------- /linuxdoc/rstFlatTable.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | # 3 | # pylint: disable=missing-docstring, arguments-differ, invalid-name 4 | # pylint: disable=too-many-arguments, too-many-locals, too-many-branches 5 | # pylint: disable=too-many-nested-blocks, useless-object-inheritance 6 | 7 | """\ 8 | flat-table 9 | ~~~~~~~~~~ 10 | 11 | Implementation of the ``flat-table`` reST-directive. User documentation see 12 | :ref:`rest-flat-table` 13 | 14 | """ 15 | 16 | # ============================================================================== 17 | # imports 18 | # ============================================================================== 19 | 20 | from docutils import nodes 21 | from docutils.parsers.rst import directives, roles 22 | from docutils.parsers.rst.directives.tables import Table, align 23 | from docutils.utils import SystemMessagePropagation 24 | 25 | # ============================================================================== 26 | # common globals 27 | # ============================================================================== 28 | 29 | __version__ = "3.0" 30 | 31 | 32 | def setup(app): 33 | 34 | app.add_directive("flat-table", FlatTable) 35 | roles.register_local_role("cspan", c_span) 36 | roles.register_local_role("rspan", r_span) 37 | 38 | return dict(version=__version__, parallel_read_safe=True, parallel_write_safe=True) 39 | 40 | 41 | def c_span( # pylint: disable=unused-argument 42 | name, rawtext, text, lineno, inliner, options=None, content=None 43 | ): 44 | 45 | options = options if options is not None else {} 46 | content = content if content is not None else [] 47 | nodelist = [colSpan(span=int(text))] 48 | msglist = [] 49 | return nodelist, msglist 50 | 51 | 52 | def r_span( # pylint: disable=unused-argument 53 | name, rawtext, text, lineno, inliner, options=None, content=None 54 | ): 55 | 56 | options = options if options is not None else {} 57 | content = content if content is not None else [] 58 | nodelist = [rowSpan(span=int(text))] 59 | msglist = [] 60 | return nodelist, msglist 61 | 62 | 63 | class rowSpan(nodes.General, nodes.Element): 64 | pass 65 | 66 | 67 | class colSpan(nodes.General, nodes.Element): 68 | pass 69 | 70 | 71 | class FlatTable(Table): 72 | """FlatTable (``flat-table``) directive""" 73 | 74 | option_spec = { 75 | "name": directives.unchanged, 76 | "class": directives.class_option, 77 | "header-rows": directives.nonnegative_int, 78 | "stub-columns": directives.nonnegative_int, 79 | "width": directives.length_or_percentage_or_unitless, 80 | "widths": directives.value_or(("auto", "grid"), directives.positive_int_list), 81 | "fill-cells": directives.flag, 82 | "align": align, 83 | } 84 | 85 | def run(self): 86 | 87 | if not self.content: 88 | error = self.state_machine.reporter.error( 89 | 'The "%s" directive is empty; content required.' % self.name, 90 | nodes.literal_block(self.block_text, self.block_text), 91 | line=self.lineno, 92 | ) 93 | return [error] 94 | 95 | title, messages = self.make_title() 96 | node = nodes.Element() # anonymous container for parsing 97 | self.state.nested_parse(self.content, self.content_offset, node) 98 | 99 | tableBuilder = ListTableBuilder(self) 100 | tableBuilder.parseFlatTableNode(node) 101 | tableNode = tableBuilder.buildTableNode() 102 | self.add_name(tableNode) 103 | tableNode["classes"] += self.options.get("class", []) 104 | self.set_table_width(tableNode) 105 | if "align" in self.options: 106 | tableNode["align"] = self.options.get("align") 107 | 108 | # debug --> tableNode.asdom().toprettyxml() 109 | if title: 110 | tableNode.insert(0, title) 111 | return [tableNode] + messages 112 | 113 | 114 | class ListTableBuilder(object): 115 | """Builds a table from a double-stage list""" 116 | 117 | def __init__(self, directive): 118 | self.directive = directive 119 | self.rows = [] 120 | self.max_cols = 0 121 | 122 | def buildTableNode(self): 123 | 124 | colwidths = self.directive.get_column_widths(self.max_cols) 125 | stub_columns = self.directive.options.get("stub-columns", 0) 126 | header_rows = self.directive.options.get("header-rows", 0) 127 | 128 | table = nodes.table() 129 | if self.directive.widths == "auto": 130 | table["classes"] += ["colwidths-auto"] 131 | elif self.directive.widths: # explicitly set column widths 132 | table["classes"] += ["colwidths-given"] 133 | tgroup = nodes.tgroup(cols=len(colwidths)) 134 | table += tgroup 135 | 136 | for colwidth in colwidths: 137 | colspec = nodes.colspec(colwidth=colwidth) 138 | # ToDo: It seems, that the stub method only works well in the 139 | # absence of rowspan (observed by the html buidler, the docutils-xml 140 | # build seems OK). This is not extraordinary, because there exists 141 | # no table directive (except *this* flat-table) which allows to 142 | # define coexistent of rowspan and stubs (there was no use-case 143 | # before flat-table). This should be reviewed (later). 144 | if stub_columns: 145 | colspec.attributes["stub"] = 1 146 | stub_columns -= 1 147 | tgroup += colspec 148 | 149 | if header_rows: 150 | thead = nodes.thead() 151 | tgroup += thead 152 | for row in self.rows[:header_rows]: 153 | thead += self.buildTableRowNode(row) 154 | 155 | tbody = nodes.tbody() 156 | tgroup += tbody 157 | 158 | for row in self.rows[header_rows:]: 159 | tbody += self.buildTableRowNode(row) 160 | return table 161 | 162 | def buildTableRowNode(self, row_data, classes=None): 163 | classes = [] if classes is None else classes 164 | row = nodes.row() 165 | for cell in row_data: 166 | if cell is None: 167 | continue 168 | cspan, rspan, cellElements = cell 169 | 170 | attributes = {"classes": classes} 171 | if rspan: 172 | attributes["morerows"] = rspan 173 | if cspan: 174 | attributes["morecols"] = cspan 175 | entry = nodes.entry(**attributes) 176 | entry.extend(cellElements) 177 | row += entry 178 | return row 179 | 180 | def raiseError(self, msg): 181 | error = self.directive.state_machine.reporter.error( 182 | msg, 183 | nodes.literal_block(self.directive.block_text, self.directive.block_text), 184 | line=self.directive.lineno, 185 | ) 186 | raise SystemMessagePropagation(error) 187 | 188 | def parseFlatTableNode(self, node): 189 | """parses the node from a :py:class:`FlatTable` directive's body""" 190 | 191 | if len(node) != 1 or not isinstance(node[0], nodes.bullet_list): 192 | self.raiseError( 193 | 'Error parsing content block for the "%s" directive: ' 194 | "exactly one bullet list expected." % self.directive.name 195 | ) 196 | 197 | for rowNum, rowItem in enumerate(node[0]): 198 | row = self.parseRowItem(rowItem, rowNum) 199 | self.rows.append(row) 200 | self.roundOffTableDefinition() 201 | 202 | def roundOffTableDefinition(self): 203 | """Round off the table definition. 204 | 205 | This method rounds off the table definition in :py:attr:`rows`. 206 | 207 | * This method inserts the needed ``None`` values for the missing cells 208 | arising from spanning cells over rows and/or columns. 209 | 210 | * recount the :py:attr:`max_cols` 211 | 212 | * Autospan or fill (option ``fill-cells``) missing cells on the right 213 | side of the table-row 214 | """ 215 | 216 | y = 0 217 | while y < len(self.rows): 218 | x = 0 219 | 220 | while x < len(self.rows[y]): 221 | cell = self.rows[y][x] 222 | if cell is None: 223 | x += 1 224 | continue 225 | cspan, rspan = cell[:2] 226 | # handle colspan in current row 227 | for c in range(cspan): 228 | try: 229 | self.rows[y].insert(x + c + 1, None) 230 | except Exception: # pylint: disable=broad-except 231 | # the user sets ambiguous rowspans 232 | pass 233 | # handle colspan in spanned rows 234 | for r in range(rspan): 235 | for c in range(cspan + 1): 236 | try: 237 | self.rows[y + r + 1].insert(x + c, None) 238 | except Exception: # pylint: disable=broad-except 239 | # the user sets ambiguous rowspans 240 | pass 241 | x += 1 242 | y += 1 243 | 244 | # Insert the missing cells on the right side. For this, first 245 | # re-calculate the max columns. 246 | 247 | for row in self.rows: 248 | if self.max_cols < len(row): # pylint: disable=consider-using-max-builtin 249 | self.max_cols = len(row) 250 | 251 | # fill with empty cells or cellspan? 252 | 253 | fill_cells = False 254 | if "fill-cells" in self.directive.options: 255 | fill_cells = True 256 | 257 | for row in self.rows: 258 | x = self.max_cols - len(row) 259 | if x and not fill_cells: 260 | if row[-1] is None: 261 | row.append((x - 1, 0, [])) 262 | else: 263 | cspan, rspan, content = row[-1] 264 | row[-1] = (cspan + x, rspan, content) 265 | elif x and fill_cells: 266 | for _i in range(x): 267 | row.append((0, 0, nodes.comment())) 268 | 269 | def pprint(self): 270 | # for debugging 271 | retVal = "[ " 272 | for row in self.rows: 273 | retVal += "[ " 274 | for col in row: 275 | if col is None: 276 | retVal += "%r" % col 277 | retVal += "\n , " 278 | else: 279 | content = col[2][0].astext() 280 | if len(content) > 30: 281 | content = content[:30] + "..." 282 | retVal += "(cspan=%s, rspan=%s, %r)" % (col[0], col[1], content) 283 | retVal += "]\n , " 284 | retVal = retVal[:-2] 285 | retVal += "]\n , " 286 | retVal = retVal[:-2] 287 | return retVal + "]" 288 | 289 | def parseRowItem(self, rowItem, rowNum): 290 | row = [] 291 | childNo = 0 292 | error = False 293 | cell = None 294 | target = None 295 | 296 | for child in rowItem: 297 | if isinstance(child, (nodes.comment, nodes.system_message)): 298 | pass 299 | elif isinstance(child, nodes.target): 300 | target = child 301 | elif isinstance(child, nodes.bullet_list): 302 | childNo += 1 303 | cell = child 304 | else: 305 | error = True 306 | break 307 | 308 | if childNo != 1 or error: 309 | self.raiseError( 310 | 'Error parsing content block for the "%s" directive: ' 311 | "two-level bullet list expected, but row %s does not " 312 | "contain a second-level bullet list." 313 | % (self.directive.name, rowNum + 1) 314 | ) 315 | 316 | for cellItem in cell: 317 | cspan, rspan, cellElements = self.parseCellItem(cellItem) 318 | if target is not None: 319 | cellElements.insert(0, target) 320 | row.append((cspan, rspan, cellElements)) 321 | return row 322 | 323 | def parseCellItem(self, cellItem): 324 | # search and remove cspan, rspan colspec from the first element in 325 | # this listItem (field). 326 | cspan = rspan = 0 327 | if not len(cellItem): # pylint: disable=len-as-condition 328 | return cspan, rspan, [] 329 | for elem in cellItem[0]: 330 | if isinstance(elem, colSpan): 331 | cspan = elem.get("span") 332 | elem.parent.remove(elem) 333 | continue 334 | if isinstance(elem, rowSpan): 335 | rspan = elem.get("span") 336 | elem.parent.remove(elem) 337 | continue 338 | return cspan, rspan, cellItem[:] 339 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pyrightconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "enableTypeIgnoreComments": true, 3 | "reportAny": false, 4 | "reportExplicitAny": false, 5 | "reportIgnoreCommentWithoutRule": false, 6 | "reportUnusedCallResult": false, 7 | } 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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_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 | -------------------------------------------------------------------------------- /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 [