* [PATCH v2 00/39] Implement kernel-doc in Python
@ 2025-02-24 9:08 Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 01/39] include/asm-generic/io.h: fix kerneldoc markup Mauro Carvalho Chehab
` (39 more replies)
0 siblings, 40 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Gustavo A. R. Silva, Arnd Bergmann, Bingbu Cao,
Greg Kroah-Hartman, Kees Cook, Sakari Ailus, Takashi Sakamoto,
Tianshu Qiu, linux-arch, linux-hardening, linux-media,
linux-staging, linux1394-devel
Hi Jon,
This changeset contains the kernel-doc.py script to replace the verable
kernel-doc originally written in Perl. It replaces the first version and the
second series I sent on the top of it.
I tried to stay as close as possible of the original Perl implementation
on the first patch introducing kernel-doc.py, as it helps to double check
if each function was properly translated to Python. This have been
helpful debugging troubles that happened during the conversion.
I worked hard to make it bug-compatible with the original one. Still, its
output has a couple of differences from the original one:
- The tab expansion works better with the Python script. With that, some
outputs that contain tabs at kernel-doc markups are now different;
- The new script works better stripping blank lines. So, there are a couple
of empty new lines that are now stripped with this version;
- There is a buggy logic at kernel-doc to strip empty description and
return sections. I was not able to replicate the exact behavior. So, I ended
adding an extra logic to strip empty sections with a different algorithm.
Yet, on my tests, the results are compatible with the venerable script
output for all .. kernel-doc tags found in Documentation/. I double-checked
this by adding support to output the kernel-doc commands when V=1, and
then I ran a diff between kernel-doc.pl and kernel-doc.py for the same
command lines.
On version 2, kerneldoc.py Sphinx extension now uses the Python classes
if KERNELDOC environment var ends with kernel-doc.py. It keeps a cache
of previously-parsed files to avoid performance penalties when the same
file is added on multiple places.
This series contains:
- 4 patches fixing some kernel-doc issues. One of them is for media, but
I prefer to have this merged via your tree, as it suppresses a warning
that happens after the changes;
- 2 cleanup patches for Perl kernel-doc;
- 2 patches renaming kernel-doc to kernel-doc.pl and adding a symlink.
I opted to have the symlink in separate to make easier to review, but
feel free to merge them on a single patch if you want.
The remaining patches add the new script, converts it into a library and
addresses lots of minor compatibility issues. The last patch changes
Sphinx extension to directly use the Python classes.
The only patch that doesn't belong to this series is a patch dropping
kernel-doc.py. I opted to keep it for now, as it can help to better
test the new tools.
With such changes, if one wants to build docs with the old script,
all it is needed is to use KERNELDOC parameter, e.g.:
$ make KERNELDOC=scripts/kernel-doc.pl htmldocs
Mauro Carvalho Chehab (39):
include/asm-generic/io.h: fix kerneldoc markup
drivers: media: intel-ipu3.h: fix identation on a kernel-doc markup
drivers: firewire: firewire-cdev.h: fix identation on a kernel-doc
markup
docs: driver-api/infiniband.rst: fix Kerneldoc markup
scripts/kernel-doc: don't add not needed new lines
scripts/kernel-doc: drop dead code for Wcontents_before_sections
scripts/kernel-doc: rename it to scripts/kernel-doc.pl
scripts/kernel-doc: add a symlink to the Perl version of kernel-doc
scripts/kernel-doc.py: add a Python parser
scripts/kernel-doc.py: output warnings the same way as kerneldoc
scripts/kernel-doc.py: better handle empty sections
scripts/kernel-doc.py: properly handle struct_group macros
scripts/kernel-doc.py: move regex methods to a separate file
scripts/kernel-doc.py: move KernelDoc class to a separate file
scripts/kernel-doc.py: move KernelFiles class to a separate file
scripts/kernel-doc.py: move output classes to a separate file
scripts/kernel-doc.py: convert message output to an interactor
scripts/kernel-doc.py: move file lists to the parser function
scripts/kernel-doc.py: implement support for -no-doc-sections
scripts/kernel-doc.py: fix line number output
scripts/kernel-doc.py: fix handling of doc output check
scripts/kernel-doc.py: properly handle out_section for ReST
scripts/kernel-doc.py: postpone warnings to the output plugin
docs: add a .pylintrc file with sys path for docs scripts
docs: sphinx: kerneldoc: verbose kernel-doc command if V=1
docs: sphinx: kerneldoc: ignore "\" characters from options
docs: sphinx: kerneldoc: use kernel-doc.py script
scripts/kernel-doc.py: Set an output format for --none
scripts/kernel-doc.py: adjust some coding style issues
scripts/lib/kdoc/kdoc_parser.py: fix Python compat with < v3.13
scripts/kernel-doc.py: move modulename to man class
scripts/kernel-doc.py: properly handle KBUILD_BUILD_TIMESTAMP
scripts/lib/kdoc/kdoc_parser.py: remove a python 3.9 dependency
scripts/kernel-doc.py: Properly handle Werror and exit codes
scripts/kernel-doc.py: some coding style cleanups
scripts/kernel-doc: switch to use kernel-doc.py
scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname
scripts/kernel_doc.py: better handle exported symbols
docs: sphinx: kerneldoc: Use python class if available
.pylintrc | 2 +
Documentation/Makefile | 2 +-
Documentation/conf.py | 2 +-
Documentation/driver-api/infiniband.rst | 16 +-
Documentation/sphinx/kerneldoc.py | 183 +-
.../media/ipu3/include/uapi/intel-ipu3.h | 3 +-
include/asm-generic/io.h | 6 +-
include/uapi/linux/firewire-cdev.h | 3 +-
scripts/kernel-doc | 2447 +----------------
scripts/kernel-doc.pl | 2439 ++++++++++++++++
scripts/kernel-doc.py | 240 ++
scripts/lib/kdoc/kdoc_files.py | 281 ++
scripts/lib/kdoc/kdoc_output.py | 792 ++++++
scripts/lib/kdoc/kdoc_parser.py | 1714 ++++++++++++
scripts/lib/kdoc/kdoc_re.py | 273 ++
15 files changed, 5930 insertions(+), 2473 deletions(-)
create mode 100644 .pylintrc
mode change 100755 => 120000 scripts/kernel-doc
create mode 100755 scripts/kernel-doc.pl
create mode 100755 scripts/kernel-doc.py
create mode 100755 scripts/lib/kdoc/kdoc_files.py
create mode 100755 scripts/lib/kdoc/kdoc_output.py
create mode 100755 scripts/lib/kdoc/kdoc_parser.py
create mode 100755 scripts/lib/kdoc/kdoc_re.py
--
2.48.1
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 01/39] include/asm-generic/io.h: fix kerneldoc markup
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 02/39] drivers: media: intel-ipu3.h: fix identation on a kernel-doc markup Mauro Carvalho Chehab
` (38 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Arnd Bergmann,
linux-arch, linux-kernel
Kerneldoc requires a "-" after the name of a function for it
to be recognized as a function.
Add it.
Fix those kernel-doc warnings:
include/asm-generic/io.h:1215: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
* memset_io Set a range of I/O memory to a constant value
include/asm-generic/io.h:1227: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
* memcpy_fromio Copy a block of data from I/O memory
include/asm-generic/io.h:1239: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
* memcpy_toio Copy a block of data into I/O memory
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
include/asm-generic/io.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index a5cbbf3e26ec..3c61c29ff6ab 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -1212,7 +1212,7 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
#ifndef memset_io
/**
- * memset_io Set a range of I/O memory to a constant value
+ * memset_io - Set a range of I/O memory to a constant value
* @addr: The beginning of the I/O-memory range to set
* @val: The value to set the memory to
* @count: The number of bytes to set
@@ -1224,7 +1224,7 @@ void memset_io(volatile void __iomem *addr, int val, size_t count);
#ifndef memcpy_fromio
/**
- * memcpy_fromio Copy a block of data from I/O memory
+ * memcpy_fromio - Copy a block of data from I/O memory
* @dst: The (RAM) destination for the copy
* @src: The (I/O memory) source for the data
* @count: The number of bytes to copy
@@ -1236,7 +1236,7 @@ void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count);
#ifndef memcpy_toio
/**
- * memcpy_toio Copy a block of data into I/O memory
+ * memcpy_toio - Copy a block of data into I/O memory
* @dst: The (I/O memory) destination for the copy
* @src: The (RAM) source for the data
* @count: The number of bytes to copy
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 02/39] drivers: media: intel-ipu3.h: fix identation on a kernel-doc markup
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 01/39] include/asm-generic/io.h: fix kerneldoc markup Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 03/39] drivers: firewire: firewire-cdev.h: " Mauro Carvalho Chehab
` (37 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Bingbu Cao,
Greg Kroah-Hartman, Sakari Ailus, Tianshu Qiu, linux-kernel,
linux-media, linux-staging
The "Rule" description is part of y_calc parameter. Having a line
starting at the beginning makes it part of the function description
instead, which is not the original intent.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/staging/media/ipu3/include/uapi/intel-ipu3.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
index 4aa2797f5e3c..8b85524beb59 100644
--- a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
+++ b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
@@ -322,7 +322,8 @@ struct ipu3_uapi_ae_config {
* 0: positive, 1: negative, default 0.
* @y_calc: Pre-processing that converts Bayer quad to RGB+Y values to be
* used for building histogram. Range [0, 32], default 8.
- * Rule:
+ *
+ * Rule:
* y_gen_rate_gr + y_gen_rate_r + y_gen_rate_b + y_gen_rate_gb = 32
* A single Y is calculated based on sum of Gr/R/B/Gb based on
* their contribution ratio.
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 03/39] drivers: firewire: firewire-cdev.h: fix identation on a kernel-doc markup
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 01/39] include/asm-generic/io.h: fix kerneldoc markup Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 02/39] drivers: media: intel-ipu3.h: fix identation on a kernel-doc markup Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 04/39] docs: driver-api/infiniband.rst: fix Kerneldoc markup Mauro Carvalho Chehab
` (36 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Takashi Sakamoto,
linux-kernel, linux1394-devel
The description of @tstamp parameter has one line that starts at the
beginning. This moves such line to the description, which is not the
intent here.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
include/uapi/linux/firewire-cdev.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/firewire-cdev.h b/include/uapi/linux/firewire-cdev.h
index 1f2c9469f921..05e3aa8fa8bc 100644
--- a/include/uapi/linux/firewire-cdev.h
+++ b/include/uapi/linux/firewire-cdev.h
@@ -449,7 +449,8 @@ struct fw_cdev_event_phy_packet {
* which the packet arrived. For %FW_CDEV_EVENT_PHY_PACKET_SENT2 and non-ping packet,
* the time stamp of isochronous cycle at which the packet was sent. For ping packet,
* the tick count for round-trip time measured by 1394 OHCI controller.
- * The time stamp of isochronous cycle at which either the response was sent for
+ *
+ * The time stamp of isochronous cycle at which either the response was sent for
* %FW_CDEV_EVENT_PHY_PACKET_SENT2 or the request arrived for
* %FW_CDEV_EVENT_PHY_PACKET_RECEIVED2.
* @data: Incoming data
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 04/39] docs: driver-api/infiniband.rst: fix Kerneldoc markup
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (2 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 03/39] drivers: firewire: firewire-cdev.h: " Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 05/39] scripts/kernel-doc: don't add not needed new lines Mauro Carvalho Chehab
` (35 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
kerneldoc.py extension doesn't handle a "\" character at the end
of the line: it will just merge it to the cmd line, producing
this command:
scripts/kernel-doc -rst -enable-lineno -function iscsi_iser_pdu_alloc -function iser_initialize_task_headers -function \ -function iscsi_iser_task_init -function iscsi_iser_mtask_xmit -function iscsi_iser_task_xmit -function \ -function iscsi_iser_cleanup_task -function iscsi_iser_check_protection -function \ -function iscsi_iser_conn_create -function iscsi_iser_conn_bind -function \ -function iscsi_iser_conn_start -function iscsi_iser_conn_stop -function \ -function iscsi_iser_session_destroy -function iscsi_iser_session_create -function \ -function iscsi_iser_set_param -function iscsi_iser_ep_connect -function iscsi_iser_ep_poll -function \ -function iscsi_iser_ep_disconnect ./drivers/infiniband/ulp/iser/iscsi_iser.c
which may not work as expected.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/driver-api/infiniband.rst | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/Documentation/driver-api/infiniband.rst b/Documentation/driver-api/infiniband.rst
index 30e142ccbee9..10d8be9e74fe 100644
--- a/Documentation/driver-api/infiniband.rst
+++ b/Documentation/driver-api/infiniband.rst
@@ -77,14 +77,14 @@ iSCSI Extensions for RDMA (iSER)
:internal:
.. kernel-doc:: drivers/infiniband/ulp/iser/iscsi_iser.c
- :functions: iscsi_iser_pdu_alloc iser_initialize_task_headers \
- iscsi_iser_task_init iscsi_iser_mtask_xmit iscsi_iser_task_xmit \
- iscsi_iser_cleanup_task iscsi_iser_check_protection \
- iscsi_iser_conn_create iscsi_iser_conn_bind \
- iscsi_iser_conn_start iscsi_iser_conn_stop \
- iscsi_iser_session_destroy iscsi_iser_session_create \
- iscsi_iser_set_param iscsi_iser_ep_connect iscsi_iser_ep_poll \
- iscsi_iser_ep_disconnect
+ :functions: iscsi_iser_pdu_alloc iser_initialize_task_headers
+ iscsi_iser_task_init iscsi_iser_mtask_xmit iscsi_iser_task_xmit
+ iscsi_iser_cleanup_task iscsi_iser_check_protection
+ iscsi_iser_conn_create iscsi_iser_conn_bind
+ iscsi_iser_conn_start iscsi_iser_conn_stop
+ iscsi_iser_session_destroy iscsi_iser_session_create
+ iscsi_iser_set_param iscsi_iser_ep_connect iscsi_iser_ep_poll
+ iscsi_iser_ep_disconnect
.. kernel-doc:: drivers/infiniband/ulp/iser/iser_initiator.c
:internal:
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 05/39] scripts/kernel-doc: don't add not needed new lines
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (3 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 04/39] docs: driver-api/infiniband.rst: fix Kerneldoc markup Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 06/39] scripts/kernel-doc: drop dead code for Wcontents_before_sections Mauro Carvalho Chehab
` (34 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
This helps comparing kernel-doc output with the new .py version
of it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 2c77b914d017..d59552e1a31d 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -760,6 +760,10 @@ sub output_highlight_rst {
if ($block) {
$output .= highlight_block($block);
}
+
+ $output =~ s/^\n+//g;
+ $output =~ s/\n+$//g;
+
foreach $line (split "\n", $output) {
print $lineprefix . $line . "\n";
}
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 06/39] scripts/kernel-doc: drop dead code for Wcontents_before_sections
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (4 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 05/39] scripts/kernel-doc: don't add not needed new lines Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-03-04 16:52 ` Jonathan Corbet
2025-02-24 9:08 ` [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl Mauro Carvalho Chehab
` (33 subsequent siblings)
39 siblings, 1 reply; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
There is a warning about contents before sections, which doesn't
work, since in_doc_sect variable is always true at the point
it is checked.
Drop the dead code.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index d59552e1a31d..af6cf408b96d 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -137,7 +137,6 @@ my $verbose = 0;
my $Werror = 0;
my $Wreturn = 0;
my $Wshort_desc = 0;
-my $Wcontents_before_sections = 0;
my $output_mode = "rst";
my $output_preformatted = 0;
my $no_doc_sections = 0;
@@ -223,7 +222,6 @@ use constant {
STATE_INLINE => 7, # gathering doc outside main block
};
my $state;
-my $in_doc_sect;
my $leading_space;
# Inline documentation state
@@ -332,12 +330,9 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
$Wreturn = 1;
} elsif ($cmd eq "Wshort-desc" or $cmd eq "Wshort-description") {
$Wshort_desc = 1;
- } elsif ($cmd eq "Wcontents-before-sections") {
- $Wcontents_before_sections = 1;
} elsif ($cmd eq "Wall") {
$Wreturn = 1;
$Wshort_desc = 1;
- $Wcontents_before_sections = 1;
} elsif (($cmd eq "h") || ($cmd eq "help")) {
pod2usage(-exitval => 0, -verbose => 2);
} elsif ($cmd eq 'no-doc-sections') {
@@ -1963,7 +1958,6 @@ sub process_export_file($) {
sub process_normal() {
if (/$doc_start/o) {
$state = STATE_NAME; # next line is always the function name
- $in_doc_sect = 0;
$declaration_start_line = $. + 1;
}
}
@@ -2068,7 +2062,6 @@ sub process_body($$) {
}
if (/$doc_sect/i) { # case insensitive for supported section names
- $in_doc_sect = 1;
$newsection = $1;
$newcontents = $2;
@@ -2085,14 +2078,10 @@ sub process_body($$) {
}
if (($contents ne "") && ($contents ne "\n")) {
- if (!$in_doc_sect && $Wcontents_before_sections) {
- emit_warning("${file}:$.", "contents before sections\n");
- }
dump_section($file, $section, $contents);
$section = $section_default;
}
- $in_doc_sect = 1;
$state = STATE_BODY;
$contents = $newcontents;
$new_start_line = $.;
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (5 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 06/39] scripts/kernel-doc: drop dead code for Wcontents_before_sections Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 23:23 ` Jonathan Corbet
2025-02-24 9:08 ` [PATCH v2 08/39] scripts/kernel-doc: add a symlink to the Perl version of kernel-doc Mauro Carvalho Chehab
` (32 subsequent siblings)
39 siblings, 1 reply; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
In preparation for deprecating scripts/kernel-doc in favor of a
new version written in Perl, rename it to scripts/kernel-doc.pl.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/{kernel-doc => kernel-doc.pl} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename scripts/{kernel-doc => kernel-doc.pl} (100%)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc.pl
similarity index 100%
rename from scripts/kernel-doc
rename to scripts/kernel-doc.pl
--
2.48.1
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 08/39] scripts/kernel-doc: add a symlink to the Perl version of kernel-doc
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (6 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
` (31 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Preserve kernel-doc name, associating with the curent version
in Perl.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc | 1 +
1 file changed, 1 insertion(+)
create mode 120000 scripts/kernel-doc
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
new file mode 120000
index 000000000000..f175155c1e66
--- /dev/null
+++ b/scripts/kernel-doc
@@ -0,0 +1 @@
+kernel-doc.pl
\ No newline at end of file
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (7 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 08/39] scripts/kernel-doc: add a symlink to the Perl version of kernel-doc Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 23:38 ` Jonathan Corbet
2025-02-24 9:08 ` [PATCH v2 10/39] scripts/kernel-doc.py: output warnings the same way as kerneldoc Mauro Carvalho Chehab
` (30 subsequent siblings)
39 siblings, 1 reply; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Gustavo A. R. Silva, Mauro Carvalho Chehab,
Kees Cook, linux-hardening, linux-kernel
Maintaining kernel-doc has been a challenge, as there aren't many
perl developers among maintainers. Also, the logic there is too
complex. Having lots of global variables and using pure functions
doesn't help.
Rewrite the script in Python, placing most global variables
inside classes. This should help maintaining the script in long
term.
It also allows a better integration with kernel-doc Sphinx
extension in the future.
I opted to keep this version as close as possible to what we
have already in Perl. There are some differences though:
1. There is one regular expression that required a rewrite:
/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/
As this one uses two features that aren't available by the native
Python regular expression module (re):
- recursive patterns: ?1
- atomic grouping (?>...)
Rewrite it to use a much simpler regular expression:
/\bSTRUCT_GROUP\(([^\)]+)\)[^;]*;/
Extra care should be taken when validating this script, as such
replacement might cause some regressions.
2. The filters are now applied only during output generation.
In particular, "nosymbol" argument is only handled there.
It means that, if the same file is processed twice for
different symbols, the warnings will be duplicated.
I opted to use this behavior as it allows the Sphinx extension
to read the file(s) only once, and apply the filtering only
when producing the ReST output. This hopefully will help
to speed up doc generation
3. This version can handle multiple files and multiple directories.
So, if one just wants to produce a big output with everything
inside a file, this could be done with
$ time ./scripts/kernel-doc.py -man . 2>/dev/null >new
real 0m54.592s
user 0m53.345s
sys 0m0.997s
4. I tried to replicate as much as possible the same arguments
from kernel-doc, with about the same behavior, for the
command line parameters starting with a single dash (-parameter).
I also added one letter aliases for each parameter, and a
--parameter (sometimes with a better name).
5. There are some sutile nuances between how Perl handles
certain regular expressions. In special, the qr operatior,
which compiles a regular expression also works as a
non-capturing group. It means that some regexes like
this one:
my $type1 = qr{[\w\s]+};
needs to be mapped as:
type1 = r'(?:[\w\s]+)?'
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
TODO:
- on this RFC, the man output doesn't match yet the same output of
kernel-doc. The ReST output matches, except for some whitespaces
and suppressed empty sectionsl
- this version lacks support for -W<filter> parameters: it will just
output all warnings.
- all classes are at the same file. I want to split the classes on
multiple files for the final version, but, during development time,
it is easier to have everything on a single file, but I plan to split
classes on different files to help maintaining the script.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 2757 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 2757 insertions(+)
create mode 100755 scripts/kernel-doc.py
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
new file mode 100755
index 000000000000..5cf5ed63f215
--- /dev/null
+++ b/scripts/kernel-doc.py
@@ -0,0 +1,2757 @@
+#!/usr/bin/env python3
+# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
+# pylint: disable=C0302,C0103,C0301
+# pylint: disable=C0116,C0115,W0511,W0613
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+# TODO: implement warning filtering
+
+"""
+kernel_doc
+==========
+
+Print formatted kernel documentation to stdout
+
+Read C language source or header FILEs, extract embedded
+documentation comments, and print formatted documentation
+to standard output.
+
+The documentation comments are identified by the "/**"
+opening comment mark.
+
+See Documentation/doc-guide/kernel-doc.rst for the
+documentation comment syntax.
+"""
+
+import argparse
+import logging
+import os
+import re
+import sys
+
+from datetime import datetime
+from pprint import pformat
+
+from dateutil import tz
+
+# Local cache for regular expressions
+re_cache = {}
+
+
+class Re:
+ """
+ Helper class to simplify regex declaration and usage,
+
+ It calls re.compile for a given pattern. It also allows adding
+ regular expressions and define sub at class init time.
+
+ Regular expressions can be cached via an argument, helping to speedup
+ searches.
+ """
+
+ def _add_regex(self, string, flags):
+ if string in re_cache:
+ self.regex = re_cache[string]
+ else:
+ self.regex = re.compile(string, flags=flags)
+
+ if self.cache:
+ re_cache[string] = self.regex
+
+ def __init__(self, string, cache=True, flags=0):
+ self.cache = cache
+ self.last_match = None
+
+ self._add_regex(string, flags)
+
+ def __str__(self):
+ return self.regex.pattern
+
+ def __add__(self, other):
+ return Re(str(self) + str(other), cache=self.cache or other.cache,
+ flags=self.regex.flags | other.regex.flags)
+
+ def match(self, string):
+ self.last_match = self.regex.match(string)
+ return self.last_match
+
+ def search(self, string):
+ self.last_match = self.regex.search(string)
+ return self.last_match
+
+ def findall(self, string):
+ return self.regex.findall(string)
+
+ def split(self, string):
+ return self.regex.split(string)
+
+ def sub(self, sub, string, count=0):
+ return self.regex.sub(sub, string, count=count)
+
+ def group(self, num):
+ return self.last_match.group(num)
+
+#
+# Regular expressions used to parse kernel-doc markups at KernelDoc class.
+#
+# Let's declare them in lowercase outside any class to make easier to
+# convert from the python script.
+#
+# As those are evaluated at the beginning, no need to cache them
+#
+
+
+# Allow whitespace at end of comment start.
+doc_start = Re(r'^/\*\*\s*$', cache=False)
+
+doc_end = Re(r'\*/', cache=False)
+doc_com = Re(r'\s*\*\s*', cache=False)
+doc_com_body = Re(r'\s*\* ?', cache=False)
+doc_decl = doc_com + Re(r'(\w+)', cache=False)
+
+# @params and a strictly limited set of supported section names
+# Specifically:
+# Match @word:
+# @...:
+# @{section-name}:
+# while trying to not match literal block starts like "example::"
+#
+doc_sect = doc_com + \
+ Re(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$',
+ flags=re.I, cache=False)
+
+doc_content = doc_com_body + Re(r'(.*)', cache=False)
+doc_block = doc_com + Re(r'DOC:\s*(.*)?', cache=False)
+doc_inline_start = Re(r'^\s*/\*\*\s*$', cache=False)
+doc_inline_sect = Re(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False)
+doc_inline_end = Re(r'^\s*\*/\s*$', cache=False)
+doc_inline_oneline = Re(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False)
+function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
+attribute = Re(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)",
+ flags=re.I | re.S, cache=False)
+
+# match expressions used to find embedded type information
+type_constant = Re(r"\b``([^\`]+)``\b", cache=False)
+type_constant2 = Re(r"\%([-_*\w]+)", cache=False)
+type_func = Re(r"(\w+)\(\)", cache=False)
+type_param = Re(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+type_param_ref = Re(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+
+# Special RST handling for func ptr params
+type_fp_param = Re(r"\@(\w+)\(\)", cache=False)
+
+# Special RST handling for structs with func ptr params
+type_fp_param2 = Re(r"\@(\w+->\S+)\(\)", cache=False)
+
+type_env = Re(r"(\$\w+)", cache=False)
+type_enum = Re(r"\&(enum\s*([_\w]+))", cache=False)
+type_struct = Re(r"\&(struct\s*([_\w]+))", cache=False)
+type_typedef = Re(r"\&(typedef\s*([_\w]+))", cache=False)
+type_union = Re(r"\&(union\s*([_\w]+))", cache=False)
+type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
+type_fallback = Re(r"\&([_\w]+)", cache=False)
+type_member_func = type_member + Re(r"\(\)", cache=False)
+
+export_symbol = Re(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False)
+export_symbol_ns = Re(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False)
+
+class KernelDoc:
+ # Parser states
+ STATE_NORMAL = 0 # normal code
+ STATE_NAME = 1 # looking for function name
+ STATE_BODY_MAYBE = 2 # body - or maybe more description
+ STATE_BODY = 3 # the body of the comment
+ STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
+ STATE_PROTO = 5 # scanning prototype
+ STATE_DOCBLOCK = 6 # documentation block
+ STATE_INLINE = 7 # gathering doc outside main block
+
+ st_name = [
+ "NORMAL",
+ "NAME",
+ "BODY_MAYBE",
+ "BODY",
+ "BODY_WITH_BLANK_LINE",
+ "PROTO",
+ "DOCBLOCK",
+ "INLINE",
+ ]
+
+ # Inline documentation state
+ STATE_INLINE_NA = 0 # not applicable ($state != STATE_INLINE)
+ STATE_INLINE_NAME = 1 # looking for member name (@foo:)
+ STATE_INLINE_TEXT = 2 # looking for member documentation
+ STATE_INLINE_END = 3 # done
+ STATE_INLINE_ERROR = 4 # error - Comment without header was found.
+ # Spit a warning as it's not
+ # proper kernel-doc and ignore the rest.
+
+ st_inline_name = [
+ "",
+ "_NAME",
+ "_TEXT",
+ "_END",
+ "_ERROR",
+ ]
+
+ # Section names
+
+ section_default = "Description" # default section
+ section_intro = "Introduction"
+ section_context = "Context"
+ section_return = "Return"
+
+ undescribed = "-- undescribed --"
+
+ def __init__(self, config, fname):
+ """Initialize internal variables"""
+
+ self.fname = fname
+ self.config = config
+
+ # Initial state for the state machines
+ self.state = self.STATE_NORMAL
+ self.inline_doc_state = self.STATE_INLINE_NA
+
+ # Store entry currently being processed
+ self.entry = None
+
+ # Place all potential outputs into an array
+ self.entries = []
+
+ def show_warnings(self, dtype, declaration_name):
+ # TODO: implement it
+
+ return True
+
+ # TODO: rename to emit_message
+ def emit_warning(self, ln, msg, warning=True):
+ """Emit a message"""
+
+ if warning:
+ self.config.log.warning("%s:%d %s", self.fname, ln, msg)
+ else:
+ self.config.log.info("%s:%d %s", self.fname, ln, msg)
+
+ def dump_section(self, start_new=True):
+ """
+ Dumps section contents to arrays/hashes intended for that purpose.
+ """
+
+ name = self.entry.section
+ contents = self.entry.contents
+
+ if type_param.match(name):
+ name = type_param.group(1)
+
+ self.entry.parameterdescs[name] = contents
+ self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+
+ self.entry.sectcheck += name + " "
+ self.entry.new_start_line = 0
+
+ elif name == "@...":
+ name = "..."
+ self.entry.parameterdescs[name] = contents
+ self.entry.sectcheck += name + " "
+ self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+ self.entry.new_start_line = 0
+
+ else:
+ if name in self.entry.sections and self.entry.sections[name] != "":
+ # Only warn on user-specified duplicate section names
+ if name != self.section_default:
+ self.emit_warning(self.entry.new_start_line,
+ f"duplicate section name '{name}'\n")
+ self.entry.sections[name] += contents
+ else:
+ self.entry.sections[name] = contents
+ self.entry.sectionlist.append(name)
+ self.entry.section_start_lines[name] = self.entry.new_start_line
+ self.entry.new_start_line = 0
+
+# self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
+
+ if start_new:
+ self.entry.section = self.section_default
+ self.entry.contents = ""
+
+ # TODO: rename it to store_declaration
+ def output_declaration(self, dtype, name, **args):
+ """
+ Stores the entry into an entry array.
+
+ The actual output and output filters will be handled elsewhere
+ """
+
+ # The implementation here is different than the original kernel-doc:
+ # instead of checking for output filters or actually output anything,
+ # it just stores the declaration content at self.entries, as the
+ # output will happen on a separate class.
+ #
+ # For now, we're keeping the same name of the function just to make
+ # easier to compare the source code of both scripts
+
+ if "declaration_start_line" not in args:
+ args["declaration_start_line"] = self.entry.declaration_start_line
+
+ args["type"] = dtype
+
+ self.entries.append((name, args))
+
+ self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
+
+ def reset_state(self, ln):
+ """
+ Ancillary routine to create a new entry. It initializes all
+ variables used by the state machine.
+ """
+
+ self.entry = argparse.Namespace
+
+ self.entry.contents = ""
+ self.entry.function = ""
+ self.entry.sectcheck = ""
+ self.entry.struct_actual = ""
+ self.entry.prototype = ""
+
+ self.entry.parameterlist = []
+ self.entry.parameterdescs = {}
+ self.entry.parametertypes = {}
+ self.entry.parameterdesc_start_lines = {}
+
+ self.entry.section_start_lines = {}
+ self.entry.sectionlist = []
+ self.entry.sections = {}
+
+ self.entry.anon_struct_union = False
+
+ self.entry.leading_space = None
+
+ # State flags
+ self.state = self.STATE_NORMAL
+ self.inline_doc_state = self.STATE_INLINE_NA
+ self.entry.brcount = 0
+
+ self.entry.in_doc_sect = False
+ self.entry.declaration_start_line = ln
+
+ def push_parameter(self, ln, decl_type, param, dtype,
+ org_arg, declaration_name):
+ if self.entry.anon_struct_union and dtype == "" and param == "}":
+ return # Ignore the ending }; from anonymous struct/union
+
+ self.entry.anon_struct_union = False
+
+ param = Re(r'[\[\)].*').sub('', param, count=1)
+
+ if dtype == "" and param.endswith("..."):
+ if Re(r'\w\.\.\.$').search(param):
+ # For named variable parameters of the form `x...`,
+ # remove the dots
+ param = param[:-3]
+ else:
+ # Handles unnamed variable parameters
+ param = "..."
+
+ if param not in self.entry.parameterdescs or \
+ not self.entry.parameterdescs[param]:
+
+ self.entry.parameterdescs[param] = "variable arguments"
+
+ elif dtype == "" and (not param or param == "void"):
+ param = "void"
+ self.entry.parameterdescs[param] = "no arguments"
+
+ elif dtype == "" and param in ["struct", "union"]:
+ # Handle unnamed (anonymous) union or struct
+ dtype = param
+ param = "{unnamed_" + param + "}"
+ self.entry.parameterdescs[param] = "anonymous\n"
+ self.entry.anon_struct_union = True
+
+ # Handle cache group enforcing variables: they do not need
+ # to be described in header files
+ elif "__cacheline_group" in param:
+ # Ignore __cacheline_group_begin and __cacheline_group_end
+ return
+
+ # Warn if parameter has no description
+ # (but ignore ones starting with # as these are not parameters
+ # but inline preprocessor statements)
+ if param not in self.entry.parameterdescs and not param.startswith("#"):
+ self.entry.parameterdescs[param] = self.undescribed
+
+ if self.show_warnings(dtype, declaration_name) and "." not in param:
+ if decl_type == 'function':
+ dname = f"{decl_type} parameter"
+ else:
+ dname = f"{decl_type} member"
+
+ self.emit_warning(ln,
+ f"{dname} '{param}' not described in '{declaration_name}'")
+
+ # Strip spaces from param so that it is one continuous string on
+ # parameterlist. This fixes a problem where check_sections()
+ # cannot find a parameter like "addr[6 + 2]" because it actually
+ # appears as "addr[6", "+", "2]" on the parameter list.
+ # However, it's better to maintain the param string unchanged for
+ # output, so just weaken the string compare in check_sections()
+ # to ignore "[blah" in a parameter string.
+
+ self.entry.parameterlist.append(param)
+ org_arg = Re(r'\s\s+').sub(' ', org_arg, count=1)
+ self.entry.parametertypes[param] = org_arg
+
+ def save_struct_actual(self, actual):
+ """
+ Strip all spaces from the actual param so that it looks like
+ one string item.
+ """
+
+ actual = Re(r'\s*').sub("", actual, count=1)
+
+ self.entry.struct_actual += actual + " "
+
+ def create_parameter_list(self, ln, decl_type, args, splitter, declaration_name):
+
+ # temporarily replace all commas inside function pointer definition
+ arg_expr = Re(r'(\([^\),]+),')
+ while arg_expr.search(args):
+ args = arg_expr.sub(r"\1#", args)
+
+ for arg in args.split(splitter):
+ # Strip comments
+ arg = Re(r'\/\*.*\*\/').sub('', arg)
+
+ # Ignore argument attributes
+ arg = Re(r'\sPOS0?\s').sub(' ', arg)
+
+ # Strip leading/trailing spaces
+ arg = arg.strip()
+ arg = Re(r'\s+').sub(' ', arg, count=1)
+
+ if arg.startswith('#'):
+ # Treat preprocessor directive as a typeless variable just to fill
+ # corresponding data structures "correctly". Catch it later in
+ # output_* subs.
+
+ # Treat preprocessor directive as a typeless variable
+ self.push_parameter(ln, decl_type, arg, "",
+ "", declaration_name)
+
+ elif Re(r'\(.+\)\s*\(').search(arg):
+ # Pointer-to-function
+
+ arg = arg.replace('#', ',')
+
+ r = Re(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)')
+ if r.match(arg):
+ param = r.group(1)
+ else:
+ self.emit_warning(ln, f"Invalid param: {arg}")
+ param = arg
+
+ dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+ self.save_struct_actual(param)
+ self.push_parameter(ln, decl_type, param, dtype,
+ arg, declaration_name)
+
+ elif Re(r'\(.+\)\s*\[').search(arg):
+ # Array-of-pointers
+
+ arg = arg.replace('#', ',')
+ r = Re(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)')
+ if r.match(arg):
+ param = r.group(1)
+ else:
+ self.emit_warning(ln, f"Invalid param: {arg}")
+ param = arg
+
+ dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+
+ self.save_struct_actual(param)
+ self.push_parameter(ln, decl_type, param, dtype,
+ arg, declaration_name)
+
+ elif arg:
+ arg = Re(r'\s*:\s*').sub(":", arg)
+ arg = Re(r'\s*\[').sub('[', arg)
+
+ args = Re(r'\s*,\s*').split(arg)
+ if args[0] and '*' in args[0]:
+ args[0] = re.sub(r'(\*+)\s*', r' \1', args[0])
+
+ first_arg = []
+ r = Re(r'^(.*\s+)(.*?\[.*\].*)$')
+ if args[0] and r.match(args[0]):
+ args.pop(0)
+ first_arg.extend(r.group(1))
+ first_arg.append(r.group(2))
+ else:
+ first_arg = Re(r'\s+').split(args.pop(0))
+
+ args.insert(0, first_arg.pop())
+ dtype = ' '.join(first_arg)
+
+ for param in args:
+ if Re(r'^(\*+)\s*(.*)').match(param):
+ r = Re(r'^(\*+)\s*(.*)')
+ if not r.match(param):
+ self.emit_warning(ln, f"Invalid param: {param}")
+ continue
+
+ param = r.group(1)
+
+ self.save_struct_actual(r.group(2))
+ self.push_parameter(ln, decl_type, r.group(2),
+ f"{dtype} {r.group(1)}",
+ arg, declaration_name)
+
+ elif Re(r'(.*?):(\w+)').search(param):
+ r = Re(r'(.*?):(\w+)')
+ if not r.match(param):
+ self.emit_warning(ln, f"Invalid param: {param}")
+ continue
+
+ if dtype != "": # Skip unnamed bit-fields
+ self.save_struct_actual(r.group(1))
+ self.push_parameter(ln, decl_type, r.group(1),
+ f"{dtype}:{r.group(2)}",
+ arg, declaration_name)
+ else:
+ self.save_struct_actual(param)
+ self.push_parameter(ln, decl_type, param, dtype,
+ arg, declaration_name)
+
+ def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck):
+ sects = sectcheck.split()
+ prms = prmscheck.split()
+ err = False
+
+ for sx in range(len(sects)): # pylint: disable=C0200
+ err = True
+ for px in range(len(prms)): # pylint: disable=C0200
+ prm_clean = prms[px]
+ prm_clean = Re(r'\[.*\]').sub('', prm_clean)
+ prm_clean = attribute.sub('', prm_clean)
+
+ # ignore array size in a parameter string;
+ # however, the original param string may contain
+ # spaces, e.g.: addr[6 + 2]
+ # and this appears in @prms as "addr[6" since the
+ # parameter list is split at spaces;
+ # hence just ignore "[..." for the sections check;
+ prm_clean = Re(r'\[.*').sub('', prm_clean)
+
+ if prm_clean == sects[sx]:
+ err = False
+ break
+
+ if err:
+ if decl_type == 'function':
+ dname = f"{decl_type} parameter"
+ else:
+ dname = f"{decl_type} member"
+
+ self.emit_warning(ln,
+ f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
+
+ def check_return_section(self, ln, declaration_name, return_type):
+
+ if not self.config.wreturn:
+ return
+
+ # Ignore an empty return type (It's a macro)
+ # Ignore functions with a "void" return type (but not "void *")
+ if not return_type or Re(r'void\s*\w*\s*$').search(return_type):
+ return
+
+ if not self.entry.sections.get("Return", None):
+ self.emit_warning(ln,
+ f"No description found for return value of '{declaration_name}'")
+
+ def dump_struct(self, ln, proto):
+ """
+ Store an entry for an struct or union
+ """
+
+ type_pattern = r'(struct|union)'
+
+ qualifiers = [
+ "__attribute__",
+ "__packed",
+ "__aligned",
+ "____cacheline_aligned_in_smp",
+ "____cacheline_aligned",
+ ]
+
+ definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?"
+ struct_members = Re(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)')
+
+ # Extract struct/union definition
+ members = None
+ declaration_name = None
+ decl_type = None
+
+ r = Re(type_pattern + r'\s+(\w+)\s*' + definition_body)
+ if r.search(proto):
+ decl_type = r.group(1)
+ declaration_name = r.group(2)
+ members = r.group(3)
+ else:
+ r = Re(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;')
+
+ if r.search(proto):
+ decl_type = r.group(1)
+ declaration_name = r.group(3)
+ members = r.group(2)
+
+ if not members:
+ self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
+ self.config.errors += 1
+ return
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln,
+ f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
+ return
+
+ args_pattern =r'([^,)]+)'
+
+ sub_prefixes = [
+ (Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''),
+ (Re(r'\/\*\s*private:.*', re.S| re.I), ''),
+
+ # Strip comments
+ (Re(r'\/\*.*?\*\/', re.S), ''),
+
+ # Strip attributes
+ (attribute, ' '),
+ (Re(r'\s*__aligned\s*\([^;]*\)', re.S), ' '),
+ (Re(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '),
+ (Re(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '),
+ (Re(r'\s*__packed\s*', re.S), ' '),
+ (Re(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '),
+ (Re(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
+ (Re(r'\s*____cacheline_aligned', re.S), ' '),
+
+ # Unwrap struct_group() based on this definition:
+ # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
+ # which has variants like: struct_group(NAME, MEMBERS...)
+
+ (Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
+ (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
+ (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
+ (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
+
+ # This is incompatible with Python re, as it uses:
+ # recursive patterns ((?1)) and atomic grouping ((?>...)):
+ # '\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;'
+ # Let's see if this works instead:
+ (Re(r'\bSTRUCT_GROUP\(([^\)]+)\)[^;]*;', re.S), r'\1'),
+
+ # Replace macros
+ (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
+ (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
+ (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
+ (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
+ (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
+ (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
+ (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'),
+ (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'),
+ (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),
+ ]
+
+ for search, sub in sub_prefixes:
+ members = search.sub(sub, members)
+
+ # Keeps the original declaration as-is
+ declaration = members
+
+ # Split nested struct/union elements
+ #
+ # This loop was simpler at the original kernel-doc perl version, as
+ # while ($members =~ m/$struct_members/) { ... }
+ # reads 'members' string on each interaction.
+ #
+ # Python behavior is different: it parses 'members' only once,
+ # creating a list of tuples from the first interaction.
+ #
+ # On other words, this won't get nested structs.
+ #
+ # So, we need to have an extra loop on Python to override such
+ # re limitation.
+
+ while True:
+ tuples = struct_members.findall(members)
+ if not tuples:
+ break
+
+ for t in tuples:
+ newmember = ""
+ maintype = t[0]
+ s_ids = t[5]
+ content = t[3]
+
+ oldmember = "".join(t)
+
+ for s_id in s_ids.split(','):
+ s_id = s_id.strip()
+
+ newmember += f"{maintype} {s_id}; "
+ s_id = Re(r'[:\[].*').sub('', s_id)
+ s_id = Re(r'^\s*\**(\S+)\s*').sub(r'\1', s_id)
+
+ for arg in content.split(';'):
+ arg = arg.strip()
+
+ if not arg:
+ continue
+
+ r = Re(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)')
+ if r.match(arg):
+ # Pointer-to-function
+ dtype = r.group(1)
+ name = r.group(2)
+ extra = r.group(3)
+
+ if not name:
+ continue
+
+ if not s_id:
+ # Anonymous struct/union
+ newmember += f"{dtype}{name}{extra}; "
+ else:
+ newmember += f"{dtype}{s_id}.{name}{extra}; "
+
+ else:
+ arg = arg.strip()
+ # Handle bitmaps
+ arg = Re(r':\s*\d+\s*').sub('', arg)
+
+ # Handle arrays
+ arg = Re(r'\[.*\]').sub('', arg)
+
+ # Handle multiple IDs
+ arg = Re(r'\s*,\s*').sub(',', arg)
+
+
+ r = Re(r'(.*)\s+([\S+,]+)')
+
+ if r.search(arg):
+ dtype = r.group(1)
+ names = r.group(2)
+ else:
+ newmember += f"{arg}; "
+ continue
+
+ for name in names.split(','):
+ name = Re(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip()
+
+ if not name:
+ continue
+
+ if not s_id:
+ # Anonymous struct/union
+ newmember += f"{dtype} {name}; "
+ else:
+ newmember += f"{dtype} {s_id}.{name}; "
+
+ members = members.replace(oldmember, newmember)
+
+ # Ignore other nested elements, like enums
+ members = re.sub(r'(\{[^\{\}]*\})', '', members)
+
+ self.create_parameter_list(ln, decl_type, members, ';',
+ declaration_name)
+ self.check_sections(ln, declaration_name, decl_type,
+ self.entry.sectcheck, self.entry.struct_actual)
+
+ # Adjust declaration for better display
+ declaration = Re(r'([\{;])').sub(r'\1\n', declaration)
+ declaration = Re(r'\}\s+;').sub('};', declaration)
+
+ # Better handle inlined enums
+ while True:
+ r = Re(r'(enum\s+\{[^\}]+),([^\n])')
+ if not r.search(declaration):
+ break
+
+ declaration = r.sub(r'\1,\n\2', declaration)
+
+ def_args = declaration.split('\n')
+ level = 1
+ declaration = ""
+ for clause in def_args:
+
+ clause = clause.strip()
+ clause = Re(r'\s+').sub(' ', clause, count=1)
+
+ if not clause:
+ continue
+
+ if '}' in clause and level > 1:
+ level -= 1
+
+ if not Re(r'^\s*#').match(clause):
+ declaration += "\t" * level
+
+ declaration += "\t" + clause + "\n"
+ if "{" in clause and "}" not in clause:
+ level += 1
+
+ self.output_declaration(decl_type, declaration_name,
+ struct=declaration_name,
+ module=self.entry.modulename,
+ definition=declaration,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+
+ def dump_enum(self, ln, proto):
+
+ # Ignore members marked private
+ proto = Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto)
+ proto = Re(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto)
+
+ # Strip comments
+ proto = Re(r'\/\*.*?\*\/', flags=re.S).sub('', proto)
+
+ # Strip #define macros inside enums
+ proto = Re(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto)
+
+ members = None
+ declaration_name = None
+
+ r = Re(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;')
+ if r.search(proto):
+ declaration_name = r.group(2)
+ members = r.group(1).rstrip()
+ else:
+ r = Re(r'enum\s+(\w*)\s*\{(.*)\}')
+ if r.match(proto):
+ declaration_name = r.group(1)
+ members = r.group(2).rstrip()
+
+ if not members:
+ self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
+ self.config.errors += 1
+ return
+
+ if self.entry.identifier != declaration_name:
+ if self.entry.identifier == "":
+ self.emit_warning(ln,
+ f"{proto}: wrong kernel-doc identifier on prototype")
+ else:
+ self.emit_warning(ln,
+ f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
+ return
+
+ if not declaration_name:
+ declaration_name = "(anonymous)"
+
+ member_set = set()
+
+ members = Re(r'\([^;]*?[\)]').sub('', members)
+
+ for arg in members.split(','):
+ if not arg:
+ continue
+ arg = Re(r'^\s*(\w+).*').sub(r'\1', arg)
+ self.entry.parameterlist.append(arg)
+ if arg not in self.entry.parameterdescs:
+ self.entry.parameterdescs[arg] = self.undescribed
+ if self.show_warnings("enum", declaration_name):
+ self.emit_warning(ln,
+ f"Enum value '{arg}' not described in enum '{declaration_name}'")
+ member_set.add(arg)
+
+ for k in self.entry.parameterdescs:
+ if k not in member_set:
+ if self.show_warnings("enum", declaration_name):
+ self.emit_warning(ln,
+ f"Excess enum value '%{k}' description in '{declaration_name}'")
+
+ self.output_declaration('enum', declaration_name,
+ enum=declaration_name,
+ module=self.config.modulename,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+
+ def dump_declaration(self, ln, prototype):
+ if self.entry.decl_type == "enum":
+ self.dump_enum(ln, prototype)
+ return
+
+ if self.entry.decl_type == "typedef":
+ self.dump_typedef(ln, prototype)
+ return
+
+ if self.entry.decl_type in ["union", "struct"]:
+ self.dump_struct(ln, prototype)
+ return
+
+ # TODO: handle other types
+ self.output_declaration(self.entry.decl_type, prototype,
+ entry=self.entry)
+
+ def dump_function(self, ln, prototype):
+
+ func_macro = False
+ return_type = ''
+ decl_type = 'function'
+
+ # Prefixes that would be removed
+ sub_prefixes = [
+ (r"^static +", "", 0),
+ (r"^extern +", "", 0),
+ (r"^asmlinkage +", "", 0),
+ (r"^inline +", "", 0),
+ (r"^__inline__ +", "", 0),
+ (r"^__inline +", "", 0),
+ (r"^__always_inline +", "", 0),
+ (r"^noinline +", "", 0),
+ (r"^__FORTIFY_INLINE +", "", 0),
+ (r"__init +", "", 0),
+ (r"__init_or_module +", "", 0),
+ (r"__deprecated +", "", 0),
+ (r"__flatten +", "", 0),
+ (r"__meminit +", "", 0),
+ (r"__must_check +", "", 0),
+ (r"__weak +", "", 0),
+ (r"__sched +", "", 0),
+ (r"_noprof", "", 0),
+ (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0),
+ (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0),
+ (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0),
+ (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0),
+ (r"__attribute_const__ +", "", 0),
+
+ # It seems that Python support for re.X is broken:
+ # At least for me (Python 3.13), this didn't work
+# (r"""
+# __attribute__\s*\(\(
+# (?:
+# [\w\s]+ # attribute name
+# (?:\([^)]*\))? # attribute arguments
+# \s*,? # optional comma at the end
+# )+
+# \)\)\s+
+# """, "", re.X),
+
+ # So, remove whitespaces and comments from it
+ (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0),
+ ]
+
+ for search, sub, flags in sub_prefixes:
+ prototype = Re(search, flags).sub(sub, prototype)
+
+ # Macros are a special case, as they change the prototype format
+ new_proto = Re(r"^#\s*define\s+").sub("", prototype)
+ if new_proto != prototype:
+ is_define_proto = True
+ prototype = new_proto
+ else:
+ is_define_proto = False
+
+ # Yes, this truly is vile. We are looking for:
+ # 1. Return type (may be nothing if we're looking at a macro)
+ # 2. Function name
+ # 3. Function parameters.
+ #
+ # All the while we have to watch out for function pointer parameters
+ # (which IIRC is what the two sections are for), C types (these
+ # regexps don't even start to express all the possibilities), and
+ # so on.
+ #
+ # If you mess with these regexps, it's a good idea to check that
+ # the following functions' documentation still comes out right:
+ # - parport_register_device (function pointer parameters)
+ # - atomic_set (macro)
+ # - pci_match_device, __copy_to_user (long return type)
+
+ name = r'[a-zA-Z0-9_~:]+'
+ prototype_end1 = r'[^\(]*'
+ prototype_end2 = r'[^\{]*'
+ prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)'
+
+ # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group.
+ # So, this needs to be mapped in Python with (?:...)? or (?:...)+
+
+ type1 = r'(?:[\w\s]+)?'
+ type2 = r'(?:[\w\s]+\*+)+'
+
+ found = False
+
+ if is_define_proto:
+ r = Re(r'^()(' + name + r')\s+')
+
+ if r.search(prototype):
+ return_type = ''
+ declaration_name = r.group(2)
+ func_macro = True
+
+ found = True
+
+ if not found:
+ patterns = [
+ rf'^()({name})\s*{prototype_end}',
+ rf'^({type1})\s+({name})\s*{prototype_end}',
+ rf'^({type2})\s*({name})\s*{prototype_end}',
+ ]
+
+ for p in patterns:
+ r = Re(p)
+
+ if r.match(prototype):
+
+ return_type = r.group(1)
+ declaration_name = r.group(2)
+ args = r.group(3)
+
+ self.create_parameter_list(ln, decl_type, args, ',',
+ declaration_name)
+
+ found = True
+ break
+ if not found:
+ self.emit_warning(ln,
+ f"cannot understand function prototype: '{prototype}'")
+ return
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln,
+ f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
+ return
+
+ prms = " ".join(self.entry.parameterlist)
+ self.check_sections(ln, declaration_name, "function",
+ self.entry.sectcheck, prms)
+
+ self.check_return_section(ln, declaration_name, return_type)
+
+ if 'typedef' in return_type:
+ self.output_declaration(decl_type, declaration_name,
+ function=declaration_name,
+ typedef=True,
+ module=self.config.modulename,
+ functiontype=return_type,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose,
+ func_macro=func_macro)
+ else:
+ self.output_declaration(decl_type, declaration_name,
+ function=declaration_name,
+ typedef=False,
+ module=self.config.modulename,
+ functiontype=return_type,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose,
+ func_macro=func_macro)
+
+ def dump_typedef(self, ln, proto):
+ typedef_type = r'((?:\s+[\w\*]+\b){1,8})\s*'
+ typedef_ident = r'\*?\s*(\w\S+)\s*'
+ typedef_args = r'\s*\((.*)\);'
+
+ typedef1 = Re(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args)
+ typedef2 = Re(r'typedef' + typedef_type + typedef_ident + typedef_args)
+
+ # Strip comments
+ proto = Re(r'/\*.*?\*/', flags=re.S).sub('', proto)
+
+ # Parse function typedef prototypes
+ for r in [typedef1, typedef2]:
+ if not r.match(proto):
+ continue
+
+ return_type = r.group(1).strip()
+ declaration_name = r.group(2)
+ args = r.group(3)
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln,
+ f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+ return
+
+ decl_type = 'function'
+ self.create_parameter_list(ln, decl_type, args, ',', declaration_name)
+
+ self.output_declaration(decl_type, declaration_name,
+ function=declaration_name,
+ typedef=True,
+ module=self.entry.modulename,
+ functiontype=return_type,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+ return
+
+ # Handle nested parentheses or brackets
+ r = Re(r'(\(*.\)\s*|\[*.\]\s*);$')
+ while r.search(proto):
+ proto = r.sub('', proto)
+
+ # Parse simple typedefs
+ r = Re(r'typedef.*\s+(\w+)\s*;')
+ if r.match(proto):
+ declaration_name = r.group(1)
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+ return
+
+ self.output_declaration('typedef', declaration_name,
+ typedef=declaration_name,
+ module=self.entry.modulename,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+ return
+
+ self.emit_warning(ln, "error: Cannot parse typedef!")
+ self.config.errors += 1
+
+ @staticmethod
+ def process_export(function_table, line):
+ """
+ process EXPORT_SYMBOL* tags
+
+ This method is called both internally and externally, so, it
+ doesn't use self.
+ """
+
+ if export_symbol.search(line):
+ symbol = export_symbol.group(2)
+ function_table.add(symbol)
+
+ if export_symbol_ns.search(line):
+ symbol = export_symbol_ns.group(2)
+ function_table.add(symbol)
+
+ def process_normal(self, ln, line):
+ """
+ STATE_NORMAL: looking for the /** to begin everything.
+ """
+
+ if not doc_start.match(line):
+ return
+
+ # start a new entry
+ self.reset_state(ln + 1)
+ self.entry.in_doc_sect = False
+
+ # next line is always the function name
+ self.state = self.STATE_NAME
+
+ def process_name(self, ln, line):
+ """
+ STATE_NAME: Looking for the "name - description" line
+ """
+
+ if doc_block.search(line):
+ self.entry.new_start_line = ln
+
+ if not doc_block.group(1):
+ self.entry.section = self.section_intro
+ else:
+ self.entry.section = doc_block.group(1)
+
+ self.state = self.STATE_DOCBLOCK
+ return
+
+ if doc_decl.search(line):
+ self.entry.identifier = doc_decl.group(1)
+ self.entry.is_kernel_comment = False
+
+ decl_start = str(doc_com) # comment block asterisk
+ fn_type = r"(?:\w+\s*\*\s*)?" # type (for non-functions)
+ parenthesis = r"(?:\(\w*\))?" # optional parenthesis on function
+ decl_end = r"(?:[-:].*)" # end of the name part
+
+ # test for pointer declaration type, foo * bar() - desc
+ r = Re(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$")
+ if r.search(line):
+ self.entry.identifier = r.group(1)
+
+ # Test for data declaration
+ r = Re(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)")
+ if r.search(line):
+ self.entry.decl_type = r.group(1)
+ self.entry.identifier = r.group(2)
+ self.entry.is_kernel_comment = True
+ else:
+ # Look for foo() or static void foo() - description;
+ # or misspelt identifier
+
+ r1 = Re(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$")
+ r2 = Re(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$")
+
+ for r in [r1, r2]:
+ if r.search(line):
+ self.entry.identifier = r.group(1)
+ self.entry.decl_type = "function"
+
+ r = Re(r"define\s+")
+ self.entry.identifier = r.sub("", self.entry.identifier)
+ self.entry.is_kernel_comment = True
+ break
+
+ self.entry.identifier = self.entry.identifier.strip(" ")
+
+ self.state = self.STATE_BODY
+
+ # if there's no @param blocks need to set up default section here
+ self.entry.section = self.section_default
+ self.entry.new_start_line = ln + 1
+
+ r = Re("[-:](.*)")
+ if r.search(line):
+ # strip leading/trailing/multiple spaces
+ self.entry.descr = r.group(1).strip(" ")
+
+ r = Re(r"\s+")
+ self.entry.descr = r.sub(" ", self.entry.descr)
+ self.entry.declaration_purpose = self.entry.descr
+ self.state = self.STATE_BODY_MAYBE
+ else:
+ self.entry.declaration_purpose = ""
+
+ if not self.entry.is_kernel_comment:
+ self.emit_warning(ln,
+ f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
+ self.state = self.STATE_NORMAL
+
+ if not self.entry.declaration_purpose and self.config.wshort_desc:
+ self.emit_warning(ln,
+ f"missing initial short description on line:\n{line}")
+
+ if not self.entry.identifier and self.entry.decl_type != "enum":
+ self.emit_warning(ln,
+ f"wrong kernel-doc identifier on line:\n{line}")
+ self.state = self.STATE_NORMAL
+
+ if self.config.verbose:
+ self.emit_warning(ln,
+ f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
+ warning=False)
+
+ return
+
+ # Failed to find an identifier. Emit a warning
+ self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
+
+ def process_body(self, ln, line):
+ """
+ STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.
+ """
+
+ if self.state == self.STATE_BODY_WITH_BLANK_LINE:
+ r = Re(r"\s*\*\s?\S")
+ if r.match(line):
+ self.dump_section()
+ self.entry.section = self.section_default
+ self.entry.new_start_line = line
+ self.entry.contents = ""
+
+ if doc_sect.search(line):
+ self.entry.in_doc_sect = True
+ newsection = doc_sect.group(1)
+
+ if newsection.lower() in ["description", "context"]:
+ newsection = newsection.title()
+
+ # Special case: @return is a section, not a param description
+ if newsection.lower() in ["@return", "@returns",
+ "return", "returns"]:
+ newsection = "Return"
+
+ # Perl kernel-doc has a check here for contents before sections.
+ # the logic there is always false, as in_doc_sect variable is
+ # always true. So, just don't implement Wcontents_before_sections
+
+ # .title()
+ newcontents = doc_sect.group(2)
+ if not newcontents:
+ newcontents = ""
+
+ if self.entry.contents.strip("\n"):
+ self.dump_section()
+
+ self.entry.new_start_line = ln
+ self.entry.section = newsection
+ self.entry.leading_space = None
+
+ self.entry.contents = newcontents.lstrip()
+ if self.entry.contents:
+ self.entry.contents += "\n"
+
+ self.state = self.STATE_BODY
+ return
+
+ if doc_end.search(line):
+ if self.entry.contents.strip("\n"):
+ self.dump_section()
+
+ # Look for doc_com + <text> + doc_end:
+ r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
+ if r.match(line):
+ self.emit_warning(ln, f"suspicious ending line: {line}")
+
+ self.entry.prototype = ""
+ self.entry.new_start_line = ln + 1
+
+ self.state = self.STATE_PROTO
+ return
+
+ if doc_content.search(line):
+ cont = doc_content.group(1)
+
+ if cont == "":
+ if self.entry.section == self.section_context:
+ self.dump_section()
+
+ self.entry.new_start_line = ln
+ self.state = self.STATE_BODY
+ else:
+ if self.entry.section != self.section_default:
+ self.state = self.STATE_BODY_WITH_BLANK_LINE
+ else:
+ self.state = self.STATE_BODY
+
+ self.entry.contents += "\n"
+
+ elif self.state == self.STATE_BODY_MAYBE:
+
+ # Continued declaration purpose
+ self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip()
+ self.entry.declaration_purpose += " " + cont
+
+ r = Re(r"\s+")
+ self.entry.declaration_purpose = r.sub(' ',
+ self.entry.declaration_purpose)
+
+ else:
+ if self.entry.section.startswith('@') or \
+ self.entry.section == self.section_context:
+ if self.entry.leading_space is None:
+ r = Re(r'^(\s+)')
+ if r.match(cont):
+ self.entry.leading_space = len(r.group(1))
+ else:
+ self.entry.leading_space = 0
+
+ # Double-check if leading space are realy spaces
+ pos = 0
+ for i in range(0, self.entry.leading_space):
+ if cont[i] != " ":
+ break
+ pos += 1
+
+ cont = cont[pos:]
+
+ # NEW LOGIC:
+ # In case it is different, update it
+ if self.entry.leading_space != pos:
+ self.entry.leading_space = pos
+
+ self.entry.contents += cont + "\n"
+ return
+
+ # Unknown line, ignore
+ self.emit_warning(ln, f"bad line: {line}")
+
+ def process_inline(self, ln, line):
+ """STATE_INLINE: docbook comments within a prototype."""
+
+ if self.inline_doc_state == self.STATE_INLINE_NAME and \
+ doc_inline_sect.search(line):
+ self.entry.section = doc_inline_sect.group(1)
+ self.entry.new_start_line = ln
+
+ self.entry.contents = doc_inline_sect.group(2).lstrip()
+ if self.entry.contents != "":
+ self.entry.contents += "\n"
+
+ self.inline_doc_state = self.STATE_INLINE_TEXT
+ # Documentation block end */
+ return
+
+ if doc_inline_end.search(line):
+ if self.entry.contents not in ["", "\n"]:
+ self.dump_section()
+
+ self.state = self.STATE_PROTO
+ self.inline_doc_state = self.STATE_INLINE_NA
+ return
+
+ if doc_content.search(line):
+ if self.inline_doc_state == self.STATE_INLINE_TEXT:
+ self.entry.contents += doc_content.group(1) + "\n"
+ if not self.entry.contents.strip(" ").rstrip("\n"):
+ self.entry.contents = ""
+
+ elif self.inline_doc_state == self.STATE_INLINE_NAME:
+ self.emit_warning(ln,
+ f"Incorrect use of kernel-doc format: {line}")
+
+ self.inline_doc_state = self.STATE_INLINE_ERROR
+
+ def syscall_munge(self, ln, proto):
+ """
+ Handle syscall definitions
+ """
+
+ is_void = False
+
+ # Strip newlines/CR's
+ proto = re.sub(r'[\r\n]+', ' ', proto)
+
+ # Check if it's a SYSCALL_DEFINE0
+ if 'SYSCALL_DEFINE0' in proto:
+ is_void = True
+
+ # Replace SYSCALL_DEFINE with correct return type & function name
+ proto = Re(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
+
+ r = Re(r'long\s+(sys_.*?),')
+ if r.search(proto):
+ proto = proto.replace(',', '(', count=1)
+ elif is_void:
+ proto = proto.replace(')', '(void)', count=1)
+
+ # Now delete all of the odd-numbered commas in the proto
+ # so that argument types & names don't have a comma between them
+ count = 0
+ length = len(proto)
+
+ if is_void:
+ length = 0 # skip the loop if is_void
+
+ for ix in range(length):
+ if proto[ix] == ',':
+ count += 1
+ if count % 2 == 1:
+ proto = proto[:ix] + ' ' + proto[ix+1:]
+
+ return proto
+
+ def tracepoint_munge(self, ln, proto):
+ """
+ Handle tracepoint definitions
+ """
+
+ tracepointname = None
+ tracepointargs = None
+
+ # Match tracepoint name based on different patterns
+ r = Re(r'TRACE_EVENT\((.*?),')
+ if r.search(proto):
+ tracepointname = r.group(1)
+
+ r = Re(r'DEFINE_SINGLE_EVENT\((.*?),')
+ if r.search(proto):
+ tracepointname = r.group(1)
+
+ r = Re(r'DEFINE_EVENT\((.*?),(.*?),')
+ if r.search(proto):
+ tracepointname = r.group(2)
+
+ if tracepointname:
+ tracepointname = tracepointname.lstrip()
+
+ r = Re(r'TP_PROTO\((.*?)\)')
+ if r.search(proto):
+ tracepointargs = r.group(1)
+
+ if not tracepointname or not tracepointargs:
+ self.emit_warning(ln,
+ f"Unrecognized tracepoint format:\n{proto}\n")
+ else:
+ proto = f"static inline void trace_{tracepointname}({tracepointargs})"
+ self.entry.identifier = f"trace_{self.entry.identifier}"
+
+ return proto
+
+ def process_proto_function(self, ln, line):
+ """Ancillary routine to process a function prototype"""
+
+ # strip C99-style comments to end of line
+ r = Re(r"\/\/.*$", re.S)
+ line = r.sub('', line)
+
+ if Re(r'\s*#\s*define').match(line):
+ self.entry.prototype = line
+ elif line.startswith('#'):
+ # Strip other macros like #ifdef/#ifndef/#endif/...
+ pass
+ else:
+ r = Re(r'([^\{]*)')
+ if r.match(line):
+ self.entry.prototype += r.group(1) + " "
+
+ if '{' in line or ';' in line or Re(r'\s*#\s*define').match(line):
+ # strip comments
+ r = Re(r'/\*.*?\*/')
+ self.entry.prototype = r.sub('', self.entry.prototype)
+
+ # strip newlines/cr's
+ r = Re(r'[\r\n]+')
+ self.entry.prototype = r.sub(' ', self.entry.prototype)
+
+ # strip leading spaces
+ r = Re(r'^\s+')
+ self.entry.prototype = r.sub('', self.entry.prototype)
+
+ # Handle self.entry.prototypes for function pointers like:
+ # int (*pcs_config)(struct foo)
+
+ r = Re(r'^(\S+\s+)\(\s*\*(\S+)\)')
+ self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
+
+ if 'SYSCALL_DEFINE' in self.entry.prototype:
+ self.entry.prototype = self.syscall_munge(ln,
+ self.entry.prototype)
+
+ r = Re(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
+ if r.search(self.entry.prototype):
+ self.entry.prototype = self.tracepoint_munge(ln,
+ self.entry.prototype)
+
+ self.dump_function(ln, self.entry.prototype)
+ self.reset_state(ln)
+
+ def process_proto_type(self, ln, line):
+ """Ancillary routine to process a type"""
+
+ # Strip newlines/cr's.
+ line = Re(r'[\r\n]+', re.S).sub(' ', line)
+
+ # Strip leading spaces
+ line = Re(r'^\s+', re.S).sub('', line)
+
+ # Strip trailing spaces
+ line = Re(r'\s+$', re.S).sub('', line)
+
+ # Strip C99-style comments to the end of the line
+ line = Re(r"\/\/.*$", re.S).sub('', line)
+
+ # To distinguish preprocessor directive from regular declaration later.
+ if line.startswith('#'):
+ line += ";"
+
+ r = Re(r'([^\{\};]*)([\{\};])(.*)')
+ while True:
+ if r.search(line):
+ if self.entry.prototype:
+ self.entry.prototype += " "
+ self.entry.prototype += r.group(1) + r.group(2)
+
+ self.entry.brcount += r.group(2).count('{')
+ self.entry.brcount -= r.group(2).count('}')
+
+ self.entry.brcount = max(self.entry.brcount, 0)
+
+ if r.group(2) == ';' and self.entry.brcount == 0:
+ self.dump_declaration(ln, self.entry.prototype)
+ self.reset_state(ln)
+ break
+
+ line = r.group(3)
+ else:
+ self.entry.prototype += line
+ break
+
+ def process_proto(self, ln, line):
+ """STATE_PROTO: reading a function/whatever prototype."""
+
+ if doc_inline_oneline.search(line):
+ self.entry.section = doc_inline_oneline.group(1)
+ self.entry.contents = doc_inline_oneline.group(2)
+
+ if self.entry.contents != "":
+ self.entry.contents += "\n"
+ self.dump_section(start_new=False)
+
+ elif doc_inline_start.search(line):
+ self.state = self.STATE_INLINE
+ self.inline_doc_state = self.STATE_INLINE_NAME
+
+ elif self.entry.decl_type == 'function':
+ self.process_proto_function(ln, line)
+
+ else:
+ self.process_proto_type(ln, line)
+
+ def process_docblock(self, ln, line):
+ """STATE_DOCBLOCK: within a DOC: block."""
+
+ if doc_end.search(line):
+ self.dump_section()
+ self.output_declaration("doc", None,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections, module=self.config.modulename)
+ self.reset_state(ln)
+
+ elif doc_content.search(line):
+ self.entry.contents += doc_content.group(1) + "\n"
+
+ def run(self):
+ """
+ Open and process each line of a C source file.
+ he parsing is controlled via a state machine, and the line is passed
+ to a different process function depending on the state. The process
+ function may update the state as needed.
+ """
+
+ cont = False
+ prev = ""
+ prev_ln = None
+
+ try:
+ with open(self.fname, "r", encoding="utf8",
+ errors="backslashreplace") as fp:
+ for ln, line in enumerate(fp):
+
+ line = line.expandtabs().strip("\n")
+
+ # Group continuation lines on prototypes
+ if self.state == self.STATE_PROTO:
+ if line.endswith("\\"):
+ prev += line.removesuffix("\\")
+ cont = True
+
+ if not prev_ln:
+ prev_ln = ln
+
+ continue
+
+ if cont:
+ ln = prev_ln
+ line = prev + line
+ prev = ""
+ cont = False
+ prev_ln = None
+
+ self.config.log.debug("%d %s%s: %s",
+ ln, self.st_name[self.state],
+ self.st_inline_name[self.inline_doc_state],
+ line)
+
+ # TODO: not all states allow EXPORT_SYMBOL*, so this
+ # can be optimized later on to speedup parsing
+ self.process_export(self.config.function_table, line)
+
+ # Hand this line to the appropriate state handler
+ if self.state == self.STATE_NORMAL:
+ self.process_normal(ln, line)
+ elif self.state == self.STATE_NAME:
+ self.process_name(ln, line)
+ elif self.state in [self.STATE_BODY, self.STATE_BODY_MAYBE,
+ self.STATE_BODY_WITH_BLANK_LINE]:
+ self.process_body(ln, line)
+ elif self.state == self.STATE_INLINE: # scanning for inline parameters
+ self.process_inline(ln, line)
+ elif self.state == self.STATE_PROTO:
+ self.process_proto(ln, line)
+ elif self.state == self.STATE_DOCBLOCK:
+ self.process_docblock(ln, line)
+ except OSError:
+ self.config.log.error(f"Error: Cannot open file {self.fname}")
+ self.config.errors += 1
+
+
+class GlobSourceFiles:
+ """
+ Parse C source code file names and directories via an Interactor.
+
+ """
+
+ def __init__(self, srctree=None, valid_extensions=None):
+ """
+ Initialize valid extensions with a tuple.
+
+ If not defined, assume default C extensions (.c and .h)
+
+ It would be possible to use python's glob function, but it is
+ very slow, and it is not interactive. So, it would wait to read all
+ directories before actually do something.
+
+ So, let's use our own implementation.
+ """
+
+ if not valid_extensions:
+ self.extensions = (".c", ".h")
+ else:
+ self.extensions = valid_extensions
+
+ self.srctree = srctree
+
+ def _parse_dir(self, dirname):
+ """Internal function to parse files recursively"""
+
+ with os.scandir(dirname) as obj:
+ for entry in obj:
+ name = os.path.join(dirname, entry.name)
+
+ if entry.is_dir():
+ yield from self._parse_dir(name)
+
+ if not entry.is_file():
+ continue
+
+ basename = os.path.basename(name)
+
+ if not basename.endswith(self.extensions):
+ continue
+
+ yield name
+
+ def parse_files(self, file_list, file_not_found_cb):
+ for fname in file_list:
+ if self.srctree:
+ f = os.path.join(self.srctree, fname)
+ else:
+ f = fname
+
+ if os.path.isdir(f):
+ yield from self._parse_dir(f)
+ elif os.path.isfile(f):
+ yield f
+ elif file_not_found_cb:
+ file_not_found_cb(fname)
+
+
+class KernelFiles():
+
+ def parse_file(self, fname):
+
+ doc = KernelDoc(self.config, fname)
+ doc.run()
+
+ return doc
+
+ def process_export_file(self, fname):
+ try:
+ with open(fname, "r", encoding="utf8",
+ errors="backslashreplace") as fp:
+ for line in fp:
+ KernelDoc.process_export(self.config.function_table, line)
+
+ except IOError:
+ print(f"Error: Cannot open fname {fname}", fname=sys.stderr)
+ self.config.errors += 1
+
+ def file_not_found_cb(self, fname):
+ self.config.log.error("Cannot find file %s", fname)
+ self.config.errors += 1
+
+ def __init__(self, files=None, verbose=False, out_style=None,
+ werror=False, wreturn=False, wshort_desc=False,
+ wcontents_before_sections=False,
+ logger=None, modulename=None, export_file=None):
+ """Initialize startup variables and parse all files"""
+
+
+ if not verbose:
+ verbose = bool(os.environ.get("KBUILD_VERBOSE", 0))
+
+ if not modulename:
+ modulename = "Kernel API"
+
+ dt = datetime.now()
+ if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
+ # use UTC TZ
+ to_zone = tz.gettz('UTC')
+ dt = dt.astimezone(to_zone)
+
+ if not werror:
+ kcflags = os.environ.get("KCFLAGS", None)
+ if kcflags:
+ match = re.search(r"(\s|^)-Werror(\s|$)/", kcflags)
+ if match:
+ werror = True
+
+ # reading this variable is for backwards compat just in case
+ # someone was calling it with the variable from outside the
+ # kernel's build system
+ kdoc_werror = os.environ.get("KDOC_WERROR", None)
+ if kdoc_werror:
+ werror = kdoc_werror
+
+ # Set global config data used on all files
+ self.config = argparse.Namespace
+
+ self.config.verbose = verbose
+ self.config.werror = werror
+ self.config.wreturn = wreturn
+ self.config.wshort_desc = wshort_desc
+ self.config.wcontents_before_sections = wcontents_before_sections
+ self.config.modulename = modulename
+
+ self.config.function_table = set()
+ self.config.source_map = {}
+
+ if not logger:
+ self.config.log = logging.getLogger("kernel-doc")
+ else:
+ self.config.log = logger
+
+ self.config.kernel_version = os.environ.get("KERNELVERSION",
+ "unknown kernel version'")
+ self.config.src_tree = os.environ.get("SRCTREE", None)
+
+ self.out_style = out_style
+ self.export_file = export_file
+
+ # Initialize internal variables
+
+ self.config.errors = 0
+ self.results = []
+
+ self.file_list = files
+ self.files = set()
+
+ def parse(self):
+ """
+ Parse all files
+ """
+
+ glob = GlobSourceFiles(srctree=self.config.src_tree)
+
+ # Let's use a set here to avoid duplicating files
+
+ for fname in glob.parse_files(self.file_list, self.file_not_found_cb):
+ if fname in self.files:
+ continue
+
+ self.files.add(fname)
+
+ res = self.parse_file(fname)
+ self.results.append((res.fname, res.entries))
+
+ if not self.files:
+ sys.exit(1)
+
+ # If a list of export files was provided, parse EXPORT_SYMBOL*
+ # from the ones not already parsed
+
+ if self.export_file:
+ files = self.files
+
+ glob = GlobSourceFiles(srctree=self.config.src_tree)
+
+ for fname in glob.parse_files(self.export_file,
+ self.file_not_found_cb):
+ if fname not in files:
+ files.add(fname)
+
+ self.process_export_file(fname)
+
+ def out_msg(self, fname, name, arg):
+ # TODO: filter out unwanted parts
+
+ return self.out_style.msg(fname, name, arg)
+
+ def msg(self, enable_lineno=False, export=False, internal=False,
+ symbol=None, nosymbol=None):
+
+ function_table = self.config.function_table
+
+ if symbol:
+ for s in symbol:
+ function_table.add(s)
+
+ # Output none mode: only warnings will be shown
+ if not self.out_style:
+ return
+
+ self.out_style.set_config(self.config)
+
+ self.out_style.set_filter(export, internal, symbol, nosymbol,
+ function_table, enable_lineno)
+
+ for fname, arg_tuple in self.results:
+ for name, arg in arg_tuple:
+ if self.out_msg(fname, name, arg):
+ ln = arg.get("ln", 0)
+ dtype = arg.get('type', "")
+
+ self.config.log.warning("%s:%d Can't handle %s",
+ fname, ln, dtype)
+
+
+class OutputFormat:
+ # output mode.
+ OUTPUT_ALL = 0 # output all symbols and doc sections
+ OUTPUT_INCLUDE = 1 # output only specified symbols
+ OUTPUT_EXPORTED = 2 # output exported symbols
+ OUTPUT_INTERNAL = 3 # output non-exported symbols
+
+ # Virtual member to be overriden at the inherited classes
+ highlights = []
+
+ def __init__(self):
+ """Declare internal vars and set mode to OUTPUT_ALL"""
+
+ self.out_mode = self.OUTPUT_ALL
+ self.enable_lineno = None
+ self.nosymbol = {}
+ self.symbol = None
+ self.function_table = set()
+ self.config = None
+
+ def set_config(self, config):
+ self.config = config
+
+ def set_filter(self, export, internal, symbol, nosymbol, function_table,
+ enable_lineno):
+ """
+ Initialize filter variables according with the requested mode.
+
+ Only one choice is valid between export, internal and symbol.
+
+ The nosymbol filter can be used on all modes.
+ """
+
+ self.enable_lineno = enable_lineno
+
+ if symbol:
+ self.out_mode = self.OUTPUT_INCLUDE
+ function_table = symbol
+ elif export:
+ self.out_mode = self.OUTPUT_EXPORTED
+ elif internal:
+ self.out_mode = self.OUTPUT_INTERNAL
+ else:
+ self.out_mode = self.OUTPUT_ALL
+
+ if nosymbol:
+ self.nosymbol = set(nosymbol)
+
+ if function_table:
+ self.function_table = function_table
+
+ def highlight_block(self, block):
+ """
+ Apply the RST highlights to a sub-block of text.
+ """
+
+ for r, sub in self.highlights:
+ block = r.sub(sub, block)
+
+ return block
+
+ def check_doc(self, name):
+ """Check if DOC should be output"""
+
+ if self.out_mode == self.OUTPUT_ALL:
+ return True
+
+ if self.out_mode == self.OUTPUT_INCLUDE:
+ if name in self.nosymbol:
+ return False
+
+ if name in self.function_table:
+ return True
+
+ return False
+
+ def check_declaration(self, dtype, name):
+ if name in self.nosymbol:
+ return False
+
+ if self.out_mode == self.OUTPUT_ALL:
+ return True
+
+ if self.out_mode in [ self.OUTPUT_INCLUDE, self.OUTPUT_EXPORTED ]:
+ if name in self.function_table:
+ return True
+
+ if self.out_mode == self.OUTPUT_INTERNAL:
+ if dtype != "function":
+ return True
+
+ if name not in self.function_table:
+ return True
+
+ return False
+
+ def check_function(self, fname, name, args):
+ return True
+
+ def check_enum(self, fname, name, args):
+ return True
+
+ def check_typedef(self, fname, name, args):
+ return True
+
+ def msg(self, fname, name, args):
+
+ dtype = args.get('type', "")
+
+ if dtype == "doc":
+ self.out_doc(fname, name, args)
+ return False
+
+ if not self.check_declaration(dtype, name):
+ return False
+
+ if dtype == "function":
+ self.out_function(fname, name, args)
+ return False
+
+ if dtype == "enum":
+ self.out_enum(fname, name, args)
+ return False
+
+ if dtype == "typedef":
+ self.out_typedef(fname, name, args)
+ return False
+
+ if dtype in ["struct", "union"]:
+ self.out_struct(fname, name, args)
+ return False
+
+ # Warn if some type requires an output logic
+ self.config.log.warning("doesn't now how to output '%s' block",
+ dtype)
+
+ return True
+
+ # Virtual methods to be overridden by inherited classes
+ def out_doc(self, fname, name, args):
+ pass
+
+ def out_function(self, fname, name, args):
+ pass
+
+ def out_enum(self, fname, name, args):
+ pass
+
+ def out_typedef(self, fname, name, args):
+ pass
+
+ def out_struct(self, fname, name, args):
+ pass
+
+
+class RestFormat(OutputFormat):
+ # """Consts and functions used by ReST output"""
+
+ highlights = [
+ (type_constant, r"``\1``"),
+ (type_constant2, r"``\1``"),
+
+ # Note: need to escape () to avoid func matching later
+ (type_member_func, r":c:type:`\1\2\3\\(\\) <\1>`"),
+ (type_member, r":c:type:`\1\2\3 <\1>`"),
+ (type_fp_param, r"**\1\\(\\)**"),
+ (type_fp_param2, r"**\1\\(\\)**"),
+ (type_func, r"\1()"),
+ (type_enum, r":c:type:`\1 <\2>`"),
+ (type_struct, r":c:type:`\1 <\2>`"),
+ (type_typedef, r":c:type:`\1 <\2>`"),
+ (type_union, r":c:type:`\1 <\2>`"),
+
+ # in rst this can refer to any type
+ (type_fallback, r":c:type:`\1`"),
+ (type_param_ref, r"**\1\2**")
+ ]
+ blankline = "\n"
+
+ sphinx_literal = Re(r'^[^.].*::$', cache=False)
+ sphinx_cblock = Re(r'^\.\.\ +code-block::', cache=False)
+
+ def __init__(self):
+ """
+ Creates class variables.
+
+ Not really mandatory, but it is a good coding style and makes
+ pylint happy.
+ """
+
+ super().__init__()
+ self.lineprefix = ""
+
+ def print_lineno (self, ln):
+ """Outputs a line number"""
+
+ if self.enable_lineno and ln:
+ print(f".. LINENO {ln}")
+
+ def output_highlight(self, args):
+ input_text = args
+ output = ""
+ in_literal = False
+ litprefix = ""
+ block = ""
+
+ for line in input_text.strip("\n").split("\n"):
+
+ # If we're in a literal block, see if we should drop out of it.
+ # Otherwise, pass the line straight through unmunged.
+ if in_literal:
+ if line.strip(): # If the line is not blank
+ # If this is the first non-blank line in a literal block,
+ # figure out the proper indent.
+ if not litprefix:
+ r = Re(r'^(\s*)')
+ if r.match(line):
+ litprefix = '^' + r.group(1)
+ else:
+ litprefix = ""
+
+ output += line + "\n"
+ elif not Re(litprefix).match(line):
+ in_literal = False
+ else:
+ output += line + "\n"
+ else:
+ output += line + "\n"
+
+ # Not in a literal block (or just dropped out)
+ if not in_literal:
+ block += line + "\n"
+ if self.sphinx_literal.match(line) or self.sphinx_cblock.match(line):
+ in_literal = True
+ litprefix = ""
+ output += self.highlight_block(block)
+ block = ""
+
+ # Handle any remaining block
+ if block:
+ output += self.highlight_block(block)
+
+ # Print the output with the line prefix
+ for line in output.strip("\n").split("\n"):
+ print(self.lineprefix + line)
+
+ def out_section(self, args, out_reference=False):
+ """
+ Outputs a block section.
+
+ This could use some work; it's used to output the DOC: sections, and
+ starts by putting out the name of the doc section itself, but that
+ tends to duplicate a header already in the template file.
+ """
+
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+ section_start_lines = args.get('section_start_lines', {})
+
+ for section in sectionlist:
+ # Skip sections that are in the nosymbol_table
+ if section in self.nosymbol:
+ continue
+
+ if not self.out_mode == self.OUTPUT_INCLUDE:
+ if out_reference:
+ print(f".. _{section}:\n")
+
+ if not self.symbol:
+ print(f'{self.lineprefix}**{section}**\n')
+
+ self.print_lineno(section_start_lines.get(section, 0))
+ self.output_highlight(sections[section])
+ print()
+ print()
+
+ def out_doc(self, fname, name, args):
+ if not self.check_doc(name):
+ return
+
+ self.out_section(args, out_reference=True)
+
+ def out_function(self, fname, name, args):
+
+ oldprefix = self.lineprefix
+ signature = ""
+
+ func_macro = args.get('func_macro', False)
+ if func_macro:
+ signature = args['function']
+ else:
+ if args.get('functiontype'):
+ signature = args['functiontype'] + " "
+ signature += args['function'] + " ("
+
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
+
+ ln = args.get('ln', 0)
+
+ count = 0
+ for parameter in parameterlist:
+ if count != 0:
+ signature += ", "
+ count += 1
+ dtype = args['parametertypes'].get(parameter, "")
+
+ if function_pointer.search(dtype):
+ signature += function_pointer.group(1) + parameter + function_pointer.group(3)
+ else:
+ signature += dtype
+
+ if not func_macro:
+ signature += ")"
+
+ if args.get('typedef') or not args.get('functiontype'):
+ print(f".. c:macro:: {args['function']}\n")
+
+ if args.get('typedef'):
+ self.print_lineno(ln)
+ print(" **Typedef**: ", end="")
+ self.lineprefix = ""
+ self.output_highlight(args.get('purpose', ""))
+ print("\n\n**Syntax**\n")
+ print(f" ``{signature}``\n")
+ else:
+ print(f"``{signature}``\n")
+ else:
+ print(f".. c:function:: {signature}\n")
+
+ if not args.get('typedef'):
+ self.print_lineno(ln)
+ self.lineprefix = " "
+ self.output_highlight(args.get('purpose', ""))
+ print()
+
+ # Put descriptive text into a container (HTML <div>) to help set
+ # function prototypes apart
+ self.lineprefix = " "
+
+ if parameterlist:
+ print(".. container:: kernelindent\n")
+ print(f"{self.lineprefix}**Parameters**\n")
+
+ for parameter in parameterlist:
+ parameter_name = Re(r'\[.*').sub('', parameter)
+ dtype = args['parametertypes'].get(parameter, "")
+
+ if dtype:
+ print(f"{self.lineprefix}``{dtype}``")
+ else:
+ print(f"{self.lineprefix}``{parameter}``")
+
+ self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
+
+ self.lineprefix = " "
+ if parameter_name in parameterdescs and \
+ parameterdescs[parameter_name] != KernelDoc.undescribed:
+
+ self.output_highlight(parameterdescs[parameter_name])
+ print()
+ else:
+ print(f"{self.lineprefix}*undescribed*\n")
+ self.lineprefix = " "
+
+ self.out_section(args)
+ self.lineprefix = oldprefix
+
+ def out_enum(self, fname, name, args):
+
+ oldprefix = self.lineprefix
+ name = args.get('enum', '')
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ ln = args.get('ln', 0)
+
+ print(f"\n\n.. c:enum:: {name}\n")
+
+ self.print_lineno(ln)
+ self.lineprefix = " "
+ self.output_highlight(args.get('purpose', ''))
+ print()
+
+ print(".. container:: kernelindent\n")
+ outer = self.lineprefix + " "
+ self.lineprefix = outer + " "
+ print(f"{outer}**Constants**\n")
+
+ for parameter in parameterlist:
+ print(f"{outer}``{parameter}``")
+
+ if parameterdescs.get(parameter, '') != KernelDoc.undescribed:
+ self.output_highlight(parameterdescs[parameter])
+ else:
+ print(f"{self.lineprefix}*undescribed*\n")
+ print()
+
+ self.lineprefix = oldprefix
+ self.out_section(args)
+
+ def out_typedef(self, fname, name, args):
+
+ oldprefix = self.lineprefix
+ name = args.get('typedef', '')
+ ln = args.get('ln', 0)
+
+ print(f"\n\n.. c:type:: {name}\n")
+
+ self.print_lineno(ln)
+ self.lineprefix = " "
+
+ self.output_highlight(args.get('purpose', ''))
+
+ print()
+
+ self.lineprefix = oldprefix
+ self.out_section(args)
+
+ def out_struct(self, fname, name, args):
+
+ name = args.get('struct', "")
+ purpose = args.get('purpose', "")
+ declaration = args.get('definition', "")
+ dtype = args.get('type', "struct")
+ ln = args.get('ln', 0)
+
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
+
+ print(f"\n\n.. c:{dtype}:: {name}\n")
+
+ self.print_lineno(ln)
+
+ oldprefix = self.lineprefix
+ self.lineprefix += " "
+
+ self.output_highlight(purpose)
+ print()
+
+ print(".. container:: kernelindent\n")
+ print(f"{self.lineprefix}**Definition**::\n")
+
+ self.lineprefix = self.lineprefix + " "
+
+ declaration = declaration.replace("\t", self.lineprefix)
+
+ print(f"{self.lineprefix}{dtype} {name}" + ' {')
+ print(f"{declaration}{self.lineprefix}" + "};\n")
+
+ self.lineprefix = " "
+ print(f"{self.lineprefix}**Members**\n")
+ for parameter in parameterlist:
+ if not parameter or parameter.startswith("#"):
+ continue
+
+ parameter_name = parameter.split("[", maxsplit=1)[0]
+
+ if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
+ continue
+
+ self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
+
+ print(f"{self.lineprefix}``{parameter}``")
+
+ self.lineprefix = " "
+ self.output_highlight(parameterdescs[parameter_name])
+ self.lineprefix = " "
+
+ print()
+
+ print()
+
+ self.lineprefix = oldprefix
+ self.out_section(args)
+
+
+class ManFormat(OutputFormat):
+ """Consts and functions used by man pages output"""
+
+ highlights = (
+ (type_constant, r"\1"),
+ (type_constant2, r"\1"),
+ (type_func, r"\\fB\1\\fP"),
+ (type_enum, r"\\fI\1\\fP"),
+ (type_struct, r"\\fI\1\\fP"),
+ (type_typedef, r"\\fI\1\\fP"),
+ (type_union, r"\\fI\1\\fP"),
+ (type_param, r"\\fI\1\\fP"),
+ (type_param_ref, r"\\fI\1\2\\fP"),
+ (type_member, r"\\fI\1\2\3\\fP"),
+ (type_fallback, r"\\fI\1\\fP")
+ )
+ blankline = ""
+
+ def __init__(self):
+ """
+ Creates class variables.
+
+ Not really mandatory, but it is a good coding style and makes
+ pylint happy.
+ """
+
+ super().__init__()
+
+ dt = datetime.now()
+ if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
+ # use UTC TZ
+ to_zone = tz.gettz('UTC')
+ dt = dt.astimezone(to_zone)
+
+ self.man_date = dt.strftime("%B %Y")
+
+ def output_highlight(self, block):
+
+ contents = self.highlight_block(block)
+
+ if isinstance(contents, list):
+ contents = "\n".join(contents)
+
+ for line in contents.strip("\n").split("\n"):
+ line = Re(r"^\s*").sub("", line)
+
+ if line and line[0] == ".":
+ print("\\&" + line)
+ else:
+ print(line)
+
+ def out_doc(self, fname, name, args):
+ module = args.get('module')
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX')
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections.get(section))
+
+ def out_function(self, fname, name, args):
+ """output function in man"""
+
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"{args['function']} \\- {args['purpose']}")
+
+ print(".SH SYNOPSIS")
+ if args.get('functiontype', ''):
+ print(f'.B "{args['functiontype']}" {args['function']}')
+ else:
+ print(f'.B "{args['function']}')
+
+ count = 0
+ parenth = "("
+ post = ","
+
+ for parameter in parameterlist:
+ if count == len(parameterlist) - 1:
+ post = ");"
+
+ dtype = args['parametertypes'].get(parameter, "")
+ if function_pointer.match(dtype):
+ # Pointer-to-function
+ print(f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"')
+ else:
+ dtype = Re(r'([^\*])$').sub(r'\1 ', dtype)
+
+ print(f'.BI "{parenth}{dtype}" "{post}"')
+ count += 1
+ parenth = ""
+
+ if parameterlist:
+ print(".SH ARGUMENTS")
+
+ for parameter in parameterlist:
+ parameter_name = re.sub(r'\[.*', '', parameter)
+
+ print(f'.IP "{parameter}" 12')
+ self.output_highlight(parameterdescs.get(parameter_name, ""))
+
+ for section in sectionlist:
+ print(f'.SH "{section.upper()}"')
+ self.output_highlight(sections[section])
+
+ def out_enum(self, fname, name, args):
+
+ name = args.get('enum', '')
+ parameterlist = args.get('parameterlist', [])
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"enum {args['enum']} \\- {args['purpose']}")
+
+ print(".SH SYNOPSIS")
+ print(f"enum {args['enum']}" + " {")
+
+ count = 0
+ for parameter in parameterlist:
+ print(f'.br\n.BI " {parameter}"')
+ if count == len(parameterlist) - 1:
+ print("\n};")
+ else:
+ print(", \n.br")
+
+ count += 1
+
+ print(".SH Constants")
+
+ for parameter in parameterlist:
+ parameter_name = Re(r'\[.*').sub('', parameter)
+ print(f'.IP "{parameter}" 12')
+ self.output_highlight(args['parameterdescs'].get(parameter_name, ""))
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections[section])
+
+ def out_typedef(self, fname, name, args):
+ module = args.get('module')
+ typedef = args.get('typedef')
+ purpose = args.get('purpose')
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{module}" 9 "{typedef}" "{self.man_date}" "API Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"typedef {typedef} \\- {purpose}")
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections.get(section))
+
+ def out_struct(self, fname, name, args):
+ module = args.get('module')
+ struct_type = args.get('type')
+ struct_name = args.get('struct')
+ purpose = args.get('purpose')
+ definition = args.get('definition')
+ sectionlist = args.get('sectionlist', [])
+ parameterlist = args.get('parameterlist', [])
+ sections = args.get('sections', {})
+ parameterdescs = args.get('parameterdescs', {})
+
+ print(f'.TH "{module}" 9 "{struct_type} {struct_name}" "{self.man_date}" "API Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"{struct_type} {struct_name} \\- {purpose}")
+
+ # Replace tabs with two spaces and handle newlines
+ declaration = definition.replace("\t", " ")
+ declaration = Re(r"\n").sub('"\n.br\n.BI "', declaration)
+
+ print(".SH SYNOPSIS")
+ print(f"{struct_type} {struct_name} " + "{" +"\n.br")
+ print(f'.BI "{declaration}\n' + "};\n.br\n")
+
+ print(".SH Members")
+ for parameter in parameterlist:
+ if parameter.startswith("#"):
+ continue
+
+ parameter_name = re.sub(r"\[.*", "", parameter)
+
+ if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
+ continue
+
+ print(f'.IP "{parameter}" 12')
+ self.output_highlight(parameterdescs.get(parameter_name))
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections.get(section))
+
+
+# Command line interface
+
+
+DESC = """
+Read C language source or header FILEs, extract embedded documentation comments,
+and print formatted documentation to standard output.
+
+The documentation comments are identified by the "/**" opening comment mark.
+
+See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax.
+"""
+
+EXPORT_FILE_DESC = """
+Specify an additional FILE in which to look for EXPORT_SYMBOL information.
+
+May be used multiple times.
+"""
+
+EXPORT_DESC = """
+Only output documentation for the symbols that have been
+exported using EXPORT_SYMBOL() and related macros in any input
+FILE or -export-file FILE.
+"""
+
+INTERNAL_DESC = """
+Only output documentation for the symbols that have NOT been
+exported using EXPORT_SYMBOL() and related macros in any input
+FILE or -export-file FILE.
+"""
+
+FUNCTION_DESC = """
+Only output documentation for the given function or DOC: section
+title. All other functions and DOC: sections are ignored.
+
+May be used multiple times.
+"""
+
+NOSYMBOL_DESC = """
+Exclude the specified symbol from the output documentation.
+
+May be used multiple times.
+"""
+
+FILES_DESC = """
+Header and C source files to be parsed.
+"""
+
+WARN_CONTENTS_BEFORE_SECTIONS_DESC = """
+Warns if there are contents before sections (deprecated).
+
+This option is kept just for backward-compatibility, but it does nothing,
+neither here nor at the original Perl script.
+"""
+
+
+def main():
+ """Main program"""
+
+ parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
+ description=DESC)
+
+ # Normal arguments
+
+ parser.add_argument("-v", "-verbose", "--verbose", action="store_true",
+ help="Verbose output, more warnings and other information.")
+
+ parser.add_argument("-d", "-debug", "--debug", action="store_true",
+ help="Enable debug messages")
+
+ parser.add_argument("-M", "-modulename", "--modulename",
+ help="Allow setting a module name at the output.")
+
+ parser.add_argument("-l", "-enable-lineno", "--enable_lineno",
+ action="store_true",
+ help="Enable line number output (only in ReST mode)")
+
+ # Arguments to control the warning behavior
+
+ parser.add_argument("-Wreturn", "--wreturn", action="store_true",
+ help="Warns about the lack of a return markup on functions.")
+
+ parser.add_argument("-Wshort-desc", "-Wshort-description", "--wshort-desc",
+ action="store_true",
+ help="Warns if initial short description is missing")
+
+ parser.add_argument("-Wcontents-before-sections",
+ "--wcontents-before-sections", action="store_true",
+ help=WARN_CONTENTS_BEFORE_SECTIONS_DESC)
+
+ parser.add_argument("-Wall", "--wall", action="store_true",
+ help="Enable all types of warnings")
+
+ parser.add_argument("-Werror", "--werror", action="store_true",
+ help="Treat warnings as errors.")
+
+ parser.add_argument("-export-file", "--export-file", action='append',
+ help=EXPORT_FILE_DESC)
+
+ # Output format mutually-exclusive group
+
+ out_group = parser.add_argument_group("Output format selection (mutually exclusive)")
+
+ out_fmt = out_group.add_mutually_exclusive_group()
+
+ out_fmt.add_argument("-m", "-man", "--man", action="store_true",
+ help="Output troff manual page format.")
+ out_fmt.add_argument("-r", "-rst", "--rst", action="store_true",
+ help="Output reStructuredText format (default).")
+ out_fmt.add_argument("-N", "-none", "--none", action="store_true",
+ help="Do not output documentation, only warnings.")
+
+ # Output selection mutually-exclusive group
+
+ sel_group = parser.add_argument_group("Output selection (mutually exclusive)")
+ sel_mut = sel_group.add_mutually_exclusive_group()
+
+ sel_mut.add_argument("-e", "-export", "--export", action='store_true',
+ help=EXPORT_DESC)
+
+ sel_mut.add_argument("-i", "-internal", "--internal", action='store_true',
+ help=INTERNAL_DESC)
+
+ sel_mut.add_argument("-s", "-function", "--symbol", action='append',
+ help=FUNCTION_DESC)
+
+ # This one is valid for all 3 types of filter
+ parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
+ help=NOSYMBOL_DESC)
+
+ parser.add_argument("files", metavar="FILE",
+ nargs="+", help=FILES_DESC)
+
+ args = parser.parse_args()
+
+ if args.wall:
+ args.wreturn = True
+ args.wshort_desc = True
+ args.wcontents_before_sections = True
+
+ if not args.debug:
+ level = logging.INFO
+ else:
+ level = logging.DEBUG
+
+ if args.man:
+ out_style = ManFormat()
+ elif args.none:
+ out_style = None
+ else:
+ out_style = RestFormat()
+
+ logging.basicConfig(level=level, format="%(levelname)s: %(message)s")
+
+ kfiles = KernelFiles(files=args.files, verbose=args.verbose,
+ out_style=out_style, werror=args.werror,
+ wreturn=args.wreturn, wshort_desc=args.wshort_desc,
+ wcontents_before_sections=args.wcontents_before_sections,
+ modulename=args.modulename,
+ export_file=args.export_file)
+
+ kfiles.parse()
+
+ kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
+ internal=args.internal, symbol=args.symbol,
+ nosymbol=args.nosymbol)
+
+
+# Call main method
+if __name__ == "__main__":
+ main()
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 10/39] scripts/kernel-doc.py: output warnings the same way as kerneldoc
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (8 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 11/39] scripts/kernel-doc.py: better handle empty sections Mauro Carvalho Chehab
` (29 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Add a formatter to logging to produce outputs in a similar way
to kernel-doc. This should help making it more compatible with
existing scripts.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 5cf5ed63f215..8bc0470d3720 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -2640,6 +2640,11 @@ neither here nor at the original Perl script.
"""
+class MsgFormatter(logging.Formatter):
+ def format(self, record):
+ record.levelname = record.levelname.capitalize()
+ return logging.Formatter.format(self, record)
+
def main():
"""Main program"""
@@ -2724,10 +2729,19 @@ def main():
args.wshort_desc = True
args.wcontents_before_sections = True
+ logger = logging.getLogger()
+
if not args.debug:
- level = logging.INFO
+ logger.setLevel(logging.INFO)
else:
- level = logging.DEBUG
+ logger.setLevel(logging.DEBUG)
+
+ formatter = MsgFormatter('%(levelname)s: %(message)s')
+
+ handler = logging.StreamHandler()
+ handler.setFormatter(formatter)
+
+ logger.addHandler(handler)
if args.man:
out_style = ManFormat()
@@ -2736,8 +2750,6 @@ def main():
else:
out_style = RestFormat()
- logging.basicConfig(level=level, format="%(levelname)s: %(message)s")
-
kfiles = KernelFiles(files=args.files, verbose=args.verbose,
out_style=out_style, werror=args.werror,
wreturn=args.wreturn, wshort_desc=args.wshort_desc,
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 11/39] scripts/kernel-doc.py: better handle empty sections
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (9 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 10/39] scripts/kernel-doc.py: output warnings the same way as kerneldoc Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 12/39] scripts/kernel-doc.py: properly handle struct_group macros Mauro Carvalho Chehab
` (28 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
While doing the conversion, we opted to skip empty sections
(description, return), but this makes harder to see the differences
between kernel-doc (Perl) and kernel-doc.py.
Also, the logic doesn't always work properly. So, change the
way this is done by adding an extra step to remove such
sections, doing it only for Return and Description.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 31 ++++++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 8bc0470d3720..886256e87692 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -242,6 +242,19 @@ class KernelDoc:
name = self.entry.section
contents = self.entry.contents
+ # TODO: we can prevent dumping empty sections here with:
+ #
+ # if self.entry.contents.strip("\n"):
+ # if start_new:
+ # self.entry.section = self.section_default
+ # self.entry.contents = ""
+ #
+ # return
+ #
+ # But, as we want to be producing the same output of the
+ # venerable kernel-doc Perl tool, let's just output everything,
+ # at least for now
+
if type_param.match(name):
name = type_param.group(1)
@@ -298,6 +311,19 @@ class KernelDoc:
args["type"] = dtype
+ # TODO: use colletions.OrderedDict
+
+ sections = args.get('sections', {})
+ sectionlist = args.get('sectionlist', [])
+
+ # Drop empty sections
+ # TODO: improve it to emit warnings
+ for section in [ "Description", "Return" ]:
+ if section in sectionlist:
+ if not sections[section].rstrip():
+ del sections[section]
+ sectionlist.remove(section)
+
self.entries.append((name, args))
self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
@@ -401,7 +427,7 @@ class KernelDoc:
# to ignore "[blah" in a parameter string.
self.entry.parameterlist.append(param)
- org_arg = Re(r'\s\s+').sub(' ', org_arg, count=1)
+ org_arg = Re(r'\s\s+').sub(' ', org_arg)
self.entry.parametertypes[param] = org_arg
def save_struct_actual(self, actual):
@@ -1309,8 +1335,7 @@ class KernelDoc:
return
if doc_end.search(line):
- if self.entry.contents.strip("\n"):
- self.dump_section()
+ self.dump_section()
# Look for doc_com + <text> + doc_end:
r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 12/39] scripts/kernel-doc.py: properly handle struct_group macros
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (10 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 11/39] scripts/kernel-doc.py: better handle empty sections Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 13/39] scripts/kernel-doc.py: move regex methods to a separate file Mauro Carvalho Chehab
` (27 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Handing nested parenthesis with regular expressions is not an
easy task. It is even harder with Python's re module, as it
has a limited subset of regular expressions, missing more
advanced features.
We might use instead Python regex module, but still the
regular expressions are very hard to understand. So, instead,
add a logic to properly match delimiters.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 220 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 213 insertions(+), 7 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 886256e87692..3decc94edb1e 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -92,6 +92,172 @@ class Re:
def group(self, num):
return self.last_match.group(num)
+class NestedMatch:
+ """
+ Finding nested delimiters is hard with regular expressions. It is
+ even harder on Python with its normal re module, as there are several
+ advanced regular expressions that are missing.
+
+ This is the case of this pattern:
+
+ '\\bSTRUCT_GROUP(\\(((?:(?>[^)(]+)|(?1))*)\\))[^;]*;'
+
+ which is used to properly match open/close parenthesis of the
+ string search STRUCT_GROUP(),
+
+ Add a class that counts pairs of delimiters, using it to match and
+ replace nested expressions.
+
+ The original approach was suggested by:
+ https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
+
+ Although I re-implemented it to make it more generic and match 3 types
+ of delimiters. The logic checks if delimiters are paired. If not, it
+ will ignore the search string.
+ """
+
+ # TODO:
+ # Right now, regular expressions to match it are defined only up to
+ # the start delimiter, e.g.:
+ #
+ # \bSTRUCT_GROUP\(
+ #
+ # is similar to: STRUCT_GROUP\((.*)\)
+ # except that the content inside the match group is delimiter's aligned.
+ #
+ # The content inside parenthesis are converted into a single replace
+ # group (e.g. r`\1').
+ #
+ # It would be nice to change such definition to support multiple
+ # match groups, allowing a regex equivalent to.
+ #
+ # FOO\((.*), (.*), (.*)\)
+ #
+ # it is probably easier to define it not as a regular expression, but
+ # with some lexical definition like:
+ #
+ # FOO(arg1, arg2, arg3)
+
+
+ DELIMITER_PAIRS = {
+ '{': '}',
+ '(': ')',
+ '[': ']',
+ }
+
+ RE_DELIM = re.compile(r'[\{\}\[\]\(\)]')
+
+ def _search(self, regex, line):
+ """
+ Finds paired blocks for a regex that ends with a delimiter.
+
+ The suggestion of using finditer to match pairs came from:
+ https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
+ but I ended using a different implementation to align all three types
+ of delimiters and seek for an initial regular expression.
+
+ The algorithm seeks for open/close paired delimiters and place them
+ into a stack, yielding a start/stop position of each match when the
+ stack is zeroed.
+
+ The algorithm shoud work fine for properly paired lines, but will
+ silently ignore end delimiters that preceeds an start delimiter.
+ This should be OK for kernel-doc parser, as unaligned delimiters
+ would cause compilation errors. So, we don't need to rise exceptions
+ to cover such issues.
+ """
+
+ stack = []
+
+ for match_re in regex.finditer(line):
+ start = match_re.start()
+ offset = match_re.end()
+
+ d = line[offset -1]
+ if d not in self.DELIMITER_PAIRS:
+ continue
+
+ end = self.DELIMITER_PAIRS[d]
+ stack.append(end)
+
+ for match in self.RE_DELIM.finditer(line[offset:]):
+ pos = match.start() + offset
+
+ d = line[pos]
+
+ if d in self.DELIMITER_PAIRS:
+ end = self.DELIMITER_PAIRS[d]
+
+ stack.append(end)
+ continue
+
+ # Does the end delimiter match what it is expected?
+ if stack and d == stack[-1]:
+ stack.pop()
+
+ if not stack:
+ yield start, offset, pos + 1
+ break
+
+ def search(self, regex, line):
+ """
+ This is similar to re.search:
+
+ It matches a regex that it is followed by a delimiter,
+ returning occurrences only if all delimiters are paired.
+ """
+
+ for t in self._search(regex, line):
+
+ yield line[t[0]:t[2]]
+
+ def sub(self, regex, sub, line, count=0):
+ """
+ This is similar to re.sub:
+
+ It matches a regex that it is followed by a delimiter,
+ replacing occurrences only if all delimiters are paired.
+
+ if r'\1' is used, it works just like re: it places there the
+ matched paired data with the delimiter stripped.
+
+ If count is different than zero, it will replace at most count
+ items.
+ """
+ out = ""
+
+ cur_pos = 0
+ n = 0
+
+ found = False
+ for start, end, pos in self._search(regex, line):
+ out += line[cur_pos:start]
+
+ # Value, ignoring start/end delimiters
+ value = line[end:pos - 1]
+
+ # replaces \1 at the sub string, if \1 is used there
+ new_sub = sub
+ new_sub = new_sub.replace(r'\1', value)
+
+ out += new_sub
+
+ # Drop end ';' if any
+ if line[pos] == ';':
+ pos += 1
+
+ cur_pos = pos
+ n += 1
+
+ if count and count >= n:
+ break
+
+ # Append the remaining string
+ l = len(line)
+ out += line[cur_pos:l]
+
+ return out
+
#
# Regular expressions used to parse kernel-doc markups at KernelDoc class.
#
@@ -663,22 +829,49 @@ class KernelDoc:
(Re(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
(Re(r'\s*____cacheline_aligned', re.S), ' '),
- # Unwrap struct_group() based on this definition:
+ # Unwrap struct_group macros based on this definition:
# __struct_group(TAG, NAME, ATTRS, MEMBERS...)
# which has variants like: struct_group(NAME, MEMBERS...)
+ # Only MEMBERS arguments require documentation.
+ #
+ # Parsing them happens on two steps:
+ #
+ # 1. drop struct group arguments that aren't at MEMBERS,
+ # storing them as STRUCT_GROUP(MEMBERS)
+ #
+ # 2. remove STRUCT_GROUP() ancillary macro.
+ #
+ # The original logic used to remove STRUCT_GROUP() using an
+ # advanced regex:
+ #
+ # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;
+ #
+ # with two patterns that are incompatible with
+ # Python re module, as it has:
+ #
+ # - a recursive pattern: (?1)
+ # - an atomic grouping: (?>...)
+ #
+ # I tried a simpler version: but it didn't work either:
+ # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*;
+ #
+ # As it doesn't properly match the end parenthesis on some cases.
+ #
+ # So, a better solution was crafted: there's now a NestedMatch
+ # class that ensures that delimiters after a search are properly
+ # matched. So, the implementation to drop STRUCT_GROUP() will be
+ # handled in separate.
(Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
(Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
(Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
(Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
- # This is incompatible with Python re, as it uses:
- # recursive patterns ((?1)) and atomic grouping ((?>...)):
- # '\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;'
- # Let's see if this works instead:
- (Re(r'\bSTRUCT_GROUP\(([^\)]+)\)[^;]*;', re.S), r'\1'),
-
# Replace macros
+ #
+ # TODO: it is better to also move those to the NestedMatch logic,
+ # to ensure that parenthesis will be properly matched.
+
(Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
(Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
(Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
@@ -690,9 +883,22 @@ class KernelDoc:
(Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),
]
+ # Regexes here are guaranteed to have the end limiter matching
+ # the start delimiter. Yet, right now, only one replace group
+ # is allowed.
+
+ sub_nested_prefixes = [
+ (re.compile(r'\bSTRUCT_GROUP\('), r'\1'),
+ ]
+
for search, sub in sub_prefixes:
members = search.sub(sub, members)
+ nested = NestedMatch()
+
+ for search, sub in sub_nested_prefixes:
+ members = nested.sub(search, sub, members)
+
# Keeps the original declaration as-is
declaration = members
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 13/39] scripts/kernel-doc.py: move regex methods to a separate file
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (11 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 12/39] scripts/kernel-doc.py: properly handle struct_group macros Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class " Mauro Carvalho Chehab
` (26 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
In preparation for letting kerneldoc Sphinx extension to import
Python libraries, move regex ancillary classes to a separate
file.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 223 +----------------------------
scripts/lib/kdoc/kdoc_re.py | 272 ++++++++++++++++++++++++++++++++++++
2 files changed, 277 insertions(+), 218 deletions(-)
create mode 100755 scripts/lib/kdoc/kdoc_re.py
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 3decc94edb1e..faae66aa6ead 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -35,228 +35,15 @@ from pprint import pformat
from dateutil import tz
-# Local cache for regular expressions
-re_cache = {}
+# Import Python modules
+LIB_DIR = "lib/kdoc"
+SRC_DIR = os.path.dirname(os.path.realpath(__file__))
-class Re:
- """
- Helper class to simplify regex declaration and usage,
+sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
- It calls re.compile for a given pattern. It also allows adding
- regular expressions and define sub at class init time.
+from kdoc_re import Re, NestedMatch
- Regular expressions can be cached via an argument, helping to speedup
- searches.
- """
-
- def _add_regex(self, string, flags):
- if string in re_cache:
- self.regex = re_cache[string]
- else:
- self.regex = re.compile(string, flags=flags)
-
- if self.cache:
- re_cache[string] = self.regex
-
- def __init__(self, string, cache=True, flags=0):
- self.cache = cache
- self.last_match = None
-
- self._add_regex(string, flags)
-
- def __str__(self):
- return self.regex.pattern
-
- def __add__(self, other):
- return Re(str(self) + str(other), cache=self.cache or other.cache,
- flags=self.regex.flags | other.regex.flags)
-
- def match(self, string):
- self.last_match = self.regex.match(string)
- return self.last_match
-
- def search(self, string):
- self.last_match = self.regex.search(string)
- return self.last_match
-
- def findall(self, string):
- return self.regex.findall(string)
-
- def split(self, string):
- return self.regex.split(string)
-
- def sub(self, sub, string, count=0):
- return self.regex.sub(sub, string, count=count)
-
- def group(self, num):
- return self.last_match.group(num)
-
-class NestedMatch:
- """
- Finding nested delimiters is hard with regular expressions. It is
- even harder on Python with its normal re module, as there are several
- advanced regular expressions that are missing.
-
- This is the case of this pattern:
-
- '\\bSTRUCT_GROUP(\\(((?:(?>[^)(]+)|(?1))*)\\))[^;]*;'
-
- which is used to properly match open/close parenthesis of the
- string search STRUCT_GROUP(),
-
- Add a class that counts pairs of delimiters, using it to match and
- replace nested expressions.
-
- The original approach was suggested by:
- https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
-
- Although I re-implemented it to make it more generic and match 3 types
- of delimiters. The logic checks if delimiters are paired. If not, it
- will ignore the search string.
- """
-
- # TODO:
- # Right now, regular expressions to match it are defined only up to
- # the start delimiter, e.g.:
- #
- # \bSTRUCT_GROUP\(
- #
- # is similar to: STRUCT_GROUP\((.*)\)
- # except that the content inside the match group is delimiter's aligned.
- #
- # The content inside parenthesis are converted into a single replace
- # group (e.g. r`\1').
- #
- # It would be nice to change such definition to support multiple
- # match groups, allowing a regex equivalent to.
- #
- # FOO\((.*), (.*), (.*)\)
- #
- # it is probably easier to define it not as a regular expression, but
- # with some lexical definition like:
- #
- # FOO(arg1, arg2, arg3)
-
-
- DELIMITER_PAIRS = {
- '{': '}',
- '(': ')',
- '[': ']',
- }
-
- RE_DELIM = re.compile(r'[\{\}\[\]\(\)]')
-
- def _search(self, regex, line):
- """
- Finds paired blocks for a regex that ends with a delimiter.
-
- The suggestion of using finditer to match pairs came from:
- https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
- but I ended using a different implementation to align all three types
- of delimiters and seek for an initial regular expression.
-
- The algorithm seeks for open/close paired delimiters and place them
- into a stack, yielding a start/stop position of each match when the
- stack is zeroed.
-
- The algorithm shoud work fine for properly paired lines, but will
- silently ignore end delimiters that preceeds an start delimiter.
- This should be OK for kernel-doc parser, as unaligned delimiters
- would cause compilation errors. So, we don't need to rise exceptions
- to cover such issues.
- """
-
- stack = []
-
- for match_re in regex.finditer(line):
- start = match_re.start()
- offset = match_re.end()
-
- d = line[offset -1]
- if d not in self.DELIMITER_PAIRS:
- continue
-
- end = self.DELIMITER_PAIRS[d]
- stack.append(end)
-
- for match in self.RE_DELIM.finditer(line[offset:]):
- pos = match.start() + offset
-
- d = line[pos]
-
- if d in self.DELIMITER_PAIRS:
- end = self.DELIMITER_PAIRS[d]
-
- stack.append(end)
- continue
-
- # Does the end delimiter match what it is expected?
- if stack and d == stack[-1]:
- stack.pop()
-
- if not stack:
- yield start, offset, pos + 1
- break
-
- def search(self, regex, line):
- """
- This is similar to re.search:
-
- It matches a regex that it is followed by a delimiter,
- returning occurrences only if all delimiters are paired.
- """
-
- for t in self._search(regex, line):
-
- yield line[t[0]:t[2]]
-
- def sub(self, regex, sub, line, count=0):
- """
- This is similar to re.sub:
-
- It matches a regex that it is followed by a delimiter,
- replacing occurrences only if all delimiters are paired.
-
- if r'\1' is used, it works just like re: it places there the
- matched paired data with the delimiter stripped.
-
- If count is different than zero, it will replace at most count
- items.
- """
- out = ""
-
- cur_pos = 0
- n = 0
-
- found = False
- for start, end, pos in self._search(regex, line):
- out += line[cur_pos:start]
-
- # Value, ignoring start/end delimiters
- value = line[end:pos - 1]
-
- # replaces \1 at the sub string, if \1 is used there
- new_sub = sub
- new_sub = new_sub.replace(r'\1', value)
-
- out += new_sub
-
- # Drop end ';' if any
- if line[pos] == ';':
- pos += 1
-
- cur_pos = pos
- n += 1
-
- if count and count >= n:
- break
-
- # Append the remaining string
- l = len(line)
- out += line[cur_pos:l]
-
- return out
#
# Regular expressions used to parse kernel-doc markups at KernelDoc class.
diff --git a/scripts/lib/kdoc/kdoc_re.py b/scripts/lib/kdoc/kdoc_re.py
new file mode 100755
index 000000000000..45ddba8090e5
--- /dev/null
+++ b/scripts/lib/kdoc/kdoc_re.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+Regular expression ancillary classes.
+
+Those help caching regular expressions and do matching for kernel-doc.
+"""
+
+import re
+
+# Local cache for regular expressions
+re_cache = {}
+
+
+class Re:
+ """
+ Helper class to simplify regex declaration and usage,
+
+ It calls re.compile for a given pattern. It also allows adding
+ regular expressions and define sub at class init time.
+
+ Regular expressions can be cached via an argument, helping to speedup
+ searches.
+ """
+
+ def _add_regex(self, string, flags):
+ """
+ Adds a new regex or re-use it from the cache.
+ """
+
+ if string in re_cache:
+ self.regex = re_cache[string]
+ else:
+ self.regex = re.compile(string, flags=flags)
+
+ if self.cache:
+ re_cache[string] = self.regex
+
+ def __init__(self, string, cache=True, flags=0):
+ """
+ Compile a regular expression and initialize internal vars.
+ """
+
+ self.cache = cache
+ self.last_match = None
+
+ self._add_regex(string, flags)
+
+ def __str__(self):
+ """
+ Return the regular expression pattern.
+ """
+ return self.regex.pattern
+
+ def __add__(self, other):
+ """
+ Allows adding two regular expressions into one.
+ """
+
+ return Re(str(self) + str(other), cache=self.cache or other.cache,
+ flags=self.regex.flags | other.regex.flags)
+
+ def match(self, string):
+ """
+ Handles a re.match storing its results
+ """
+
+ self.last_match = self.regex.match(string)
+ return self.last_match
+
+ def search(self, string):
+ """
+ Handles a re.search storing its results
+ """
+
+ self.last_match = self.regex.search(string)
+ return self.last_match
+
+ def findall(self, string):
+ """
+ Alias to re.findall
+ """
+
+ return self.regex.findall(string)
+
+ def split(self, string):
+ """
+ Alias to re.split
+ """
+
+ return self.regex.split(string)
+
+ def sub(self, sub, string, count=0):
+ """
+ Alias to re.sub
+ """
+
+ return self.regex.sub(sub, string, count=count)
+
+ def group(self, num):
+ """
+ Returns the group results of the last match
+ """
+
+ return self.last_match.group(num)
+
+
+class NestedMatch:
+ """
+ Finding nested delimiters is hard with regular expressions. It is
+ even harder on Python with its normal re module, as there are several
+ advanced regular expressions that are missing.
+
+ This is the case of this pattern:
+
+ '\\bSTRUCT_GROUP(\\(((?:(?>[^)(]+)|(?1))*)\\))[^;]*;'
+
+ which is used to properly match open/close parenthesis of the
+ string search STRUCT_GROUP(),
+
+ Add a class that counts pairs of delimiters, using it to match and
+ replace nested expressions.
+
+ The original approach was suggested by:
+ https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
+
+ Although I re-implemented it to make it more generic and match 3 types
+ of delimiters. The logic checks if delimiters are paired. If not, it
+ will ignore the search string.
+ """
+
+ # TODO:
+ # Right now, regular expressions to match it are defined only up to
+ # the start delimiter, e.g.:
+ #
+ # \bSTRUCT_GROUP\(
+ #
+ # is similar to: STRUCT_GROUP\((.*)\)
+ # except that the content inside the match group is delimiter's aligned.
+ #
+ # The content inside parenthesis are converted into a single replace
+ # group (e.g. r`\1').
+ #
+ # It would be nice to change such definition to support multiple
+ # match groups, allowing a regex equivalent to.
+ #
+ # FOO\((.*), (.*), (.*)\)
+ #
+ # it is probably easier to define it not as a regular expression, but
+ # with some lexical definition like:
+ #
+ # FOO(arg1, arg2, arg3)
+
+ DELIMITER_PAIRS = {
+ '{': '}',
+ '(': ')',
+ '[': ']',
+ }
+
+ RE_DELIM = re.compile(r'[\{\}\[\]\(\)]')
+
+ def _search(self, regex, line):
+ """
+ Finds paired blocks for a regex that ends with a delimiter.
+
+ The suggestion of using finditer to match pairs came from:
+ https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex
+ but I ended using a different implementation to align all three types
+ of delimiters and seek for an initial regular expression.
+
+ The algorithm seeks for open/close paired delimiters and place them
+ into a stack, yielding a start/stop position of each match when the
+ stack is zeroed.
+
+ The algorithm shoud work fine for properly paired lines, but will
+ silently ignore end delimiters that preceeds an start delimiter.
+ This should be OK for kernel-doc parser, as unaligned delimiters
+ would cause compilation errors. So, we don't need to rise exceptions
+ to cover such issues.
+ """
+
+ stack = []
+
+ for match_re in regex.finditer(line):
+ start = match_re.start()
+ offset = match_re.end()
+
+ d = line[offset - 1]
+ if d not in self.DELIMITER_PAIRS:
+ continue
+
+ end = self.DELIMITER_PAIRS[d]
+ stack.append(end)
+
+ for match in self.RE_DELIM.finditer(line[offset:]):
+ pos = match.start() + offset
+
+ d = line[pos]
+
+ if d in self.DELIMITER_PAIRS:
+ end = self.DELIMITER_PAIRS[d]
+
+ stack.append(end)
+ continue
+
+ # Does the end delimiter match what it is expected?
+ if stack and d == stack[-1]:
+ stack.pop()
+
+ if not stack:
+ yield start, offset, pos + 1
+ break
+
+ def search(self, regex, line):
+ """
+ This is similar to re.search:
+
+ It matches a regex that it is followed by a delimiter,
+ returning occurrences only if all delimiters are paired.
+ """
+
+ for t in self._search(regex, line):
+
+ yield line[t[0]:t[2]]
+
+ def sub(self, regex, sub, line, count=0):
+ """
+ This is similar to re.sub:
+
+ It matches a regex that it is followed by a delimiter,
+ replacing occurrences only if all delimiters are paired.
+
+ if r'\1' is used, it works just like re: it places there the
+ matched paired data with the delimiter stripped.
+
+ If count is different than zero, it will replace at most count
+ items.
+ """
+ out = ""
+
+ cur_pos = 0
+ n = 0
+
+ for start, end, pos in self._search(regex, line):
+ out += line[cur_pos:start]
+
+ # Value, ignoring start/end delimiters
+ value = line[end:pos - 1]
+
+ # replaces \1 at the sub string, if \1 is used there
+ new_sub = sub
+ new_sub = new_sub.replace(r'\1', value)
+
+ out += new_sub
+
+ # Drop end ';' if any
+ if line[pos] == ';':
+ pos += 1
+
+ cur_pos = pos
+ n += 1
+
+ if count and count >= n:
+ break
+
+ # Append the remaining string
+ l = len(line)
+ out += line[cur_pos:l]
+
+ return out
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class to a separate file
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (12 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 13/39] scripts/kernel-doc.py: move regex methods to a separate file Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 15/39] scripts/kernel-doc.py: move KernelFiles " Mauro Carvalho Chehab
` (25 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Gustavo A. R. Silva, Mauro Carvalho Chehab,
Kees Cook, linux-hardening, linux-kernel
In preparation for letting kerneldoc Sphinx extension to import
Python libraries, move regex ancillary classes to a separate
file.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 1634 +-----------------------------
scripts/lib/kdoc/kdoc_parser.py | 1689 +++++++++++++++++++++++++++++++
2 files changed, 1691 insertions(+), 1632 deletions(-)
create mode 100755 scripts/lib/kdoc/kdoc_parser.py
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index faae66aa6ead..193a30fcfb7c 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -42,53 +42,15 @@ SRC_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
-from kdoc_re import Re, NestedMatch
+from kdoc_parser import KernelDoc, type_param
+from kdoc_re import Re
-
-#
-# Regular expressions used to parse kernel-doc markups at KernelDoc class.
-#
-# Let's declare them in lowercase outside any class to make easier to
-# convert from the python script.
-#
-# As those are evaluated at the beginning, no need to cache them
-#
-
-
-# Allow whitespace at end of comment start.
-doc_start = Re(r'^/\*\*\s*$', cache=False)
-
-doc_end = Re(r'\*/', cache=False)
-doc_com = Re(r'\s*\*\s*', cache=False)
-doc_com_body = Re(r'\s*\* ?', cache=False)
-doc_decl = doc_com + Re(r'(\w+)', cache=False)
-
-# @params and a strictly limited set of supported section names
-# Specifically:
-# Match @word:
-# @...:
-# @{section-name}:
-# while trying to not match literal block starts like "example::"
-#
-doc_sect = doc_com + \
- Re(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$',
- flags=re.I, cache=False)
-
-doc_content = doc_com_body + Re(r'(.*)', cache=False)
-doc_block = doc_com + Re(r'DOC:\s*(.*)?', cache=False)
-doc_inline_start = Re(r'^\s*/\*\*\s*$', cache=False)
-doc_inline_sect = Re(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False)
-doc_inline_end = Re(r'^\s*\*/\s*$', cache=False)
-doc_inline_oneline = Re(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False)
function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
-attribute = Re(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)",
- flags=re.I | re.S, cache=False)
# match expressions used to find embedded type information
type_constant = Re(r"\b``([^\`]+)``\b", cache=False)
type_constant2 = Re(r"\%([-_*\w]+)", cache=False)
type_func = Re(r"(\w+)\(\)", cache=False)
-type_param = Re(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
type_param_ref = Re(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
# Special RST handling for func ptr params
@@ -106,1598 +68,6 @@ type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
type_fallback = Re(r"\&([_\w]+)", cache=False)
type_member_func = type_member + Re(r"\(\)", cache=False)
-export_symbol = Re(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False)
-export_symbol_ns = Re(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False)
-
-class KernelDoc:
- # Parser states
- STATE_NORMAL = 0 # normal code
- STATE_NAME = 1 # looking for function name
- STATE_BODY_MAYBE = 2 # body - or maybe more description
- STATE_BODY = 3 # the body of the comment
- STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
- STATE_PROTO = 5 # scanning prototype
- STATE_DOCBLOCK = 6 # documentation block
- STATE_INLINE = 7 # gathering doc outside main block
-
- st_name = [
- "NORMAL",
- "NAME",
- "BODY_MAYBE",
- "BODY",
- "BODY_WITH_BLANK_LINE",
- "PROTO",
- "DOCBLOCK",
- "INLINE",
- ]
-
- # Inline documentation state
- STATE_INLINE_NA = 0 # not applicable ($state != STATE_INLINE)
- STATE_INLINE_NAME = 1 # looking for member name (@foo:)
- STATE_INLINE_TEXT = 2 # looking for member documentation
- STATE_INLINE_END = 3 # done
- STATE_INLINE_ERROR = 4 # error - Comment without header was found.
- # Spit a warning as it's not
- # proper kernel-doc and ignore the rest.
-
- st_inline_name = [
- "",
- "_NAME",
- "_TEXT",
- "_END",
- "_ERROR",
- ]
-
- # Section names
-
- section_default = "Description" # default section
- section_intro = "Introduction"
- section_context = "Context"
- section_return = "Return"
-
- undescribed = "-- undescribed --"
-
- def __init__(self, config, fname):
- """Initialize internal variables"""
-
- self.fname = fname
- self.config = config
-
- # Initial state for the state machines
- self.state = self.STATE_NORMAL
- self.inline_doc_state = self.STATE_INLINE_NA
-
- # Store entry currently being processed
- self.entry = None
-
- # Place all potential outputs into an array
- self.entries = []
-
- def show_warnings(self, dtype, declaration_name):
- # TODO: implement it
-
- return True
-
- # TODO: rename to emit_message
- def emit_warning(self, ln, msg, warning=True):
- """Emit a message"""
-
- if warning:
- self.config.log.warning("%s:%d %s", self.fname, ln, msg)
- else:
- self.config.log.info("%s:%d %s", self.fname, ln, msg)
-
- def dump_section(self, start_new=True):
- """
- Dumps section contents to arrays/hashes intended for that purpose.
- """
-
- name = self.entry.section
- contents = self.entry.contents
-
- # TODO: we can prevent dumping empty sections here with:
- #
- # if self.entry.contents.strip("\n"):
- # if start_new:
- # self.entry.section = self.section_default
- # self.entry.contents = ""
- #
- # return
- #
- # But, as we want to be producing the same output of the
- # venerable kernel-doc Perl tool, let's just output everything,
- # at least for now
-
- if type_param.match(name):
- name = type_param.group(1)
-
- self.entry.parameterdescs[name] = contents
- self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
-
- self.entry.sectcheck += name + " "
- self.entry.new_start_line = 0
-
- elif name == "@...":
- name = "..."
- self.entry.parameterdescs[name] = contents
- self.entry.sectcheck += name + " "
- self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
- self.entry.new_start_line = 0
-
- else:
- if name in self.entry.sections and self.entry.sections[name] != "":
- # Only warn on user-specified duplicate section names
- if name != self.section_default:
- self.emit_warning(self.entry.new_start_line,
- f"duplicate section name '{name}'\n")
- self.entry.sections[name] += contents
- else:
- self.entry.sections[name] = contents
- self.entry.sectionlist.append(name)
- self.entry.section_start_lines[name] = self.entry.new_start_line
- self.entry.new_start_line = 0
-
-# self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
-
- if start_new:
- self.entry.section = self.section_default
- self.entry.contents = ""
-
- # TODO: rename it to store_declaration
- def output_declaration(self, dtype, name, **args):
- """
- Stores the entry into an entry array.
-
- The actual output and output filters will be handled elsewhere
- """
-
- # The implementation here is different than the original kernel-doc:
- # instead of checking for output filters or actually output anything,
- # it just stores the declaration content at self.entries, as the
- # output will happen on a separate class.
- #
- # For now, we're keeping the same name of the function just to make
- # easier to compare the source code of both scripts
-
- if "declaration_start_line" not in args:
- args["declaration_start_line"] = self.entry.declaration_start_line
-
- args["type"] = dtype
-
- # TODO: use colletions.OrderedDict
-
- sections = args.get('sections', {})
- sectionlist = args.get('sectionlist', [])
-
- # Drop empty sections
- # TODO: improve it to emit warnings
- for section in [ "Description", "Return" ]:
- if section in sectionlist:
- if not sections[section].rstrip():
- del sections[section]
- sectionlist.remove(section)
-
- self.entries.append((name, args))
-
- self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
-
- def reset_state(self, ln):
- """
- Ancillary routine to create a new entry. It initializes all
- variables used by the state machine.
- """
-
- self.entry = argparse.Namespace
-
- self.entry.contents = ""
- self.entry.function = ""
- self.entry.sectcheck = ""
- self.entry.struct_actual = ""
- self.entry.prototype = ""
-
- self.entry.parameterlist = []
- self.entry.parameterdescs = {}
- self.entry.parametertypes = {}
- self.entry.parameterdesc_start_lines = {}
-
- self.entry.section_start_lines = {}
- self.entry.sectionlist = []
- self.entry.sections = {}
-
- self.entry.anon_struct_union = False
-
- self.entry.leading_space = None
-
- # State flags
- self.state = self.STATE_NORMAL
- self.inline_doc_state = self.STATE_INLINE_NA
- self.entry.brcount = 0
-
- self.entry.in_doc_sect = False
- self.entry.declaration_start_line = ln
-
- def push_parameter(self, ln, decl_type, param, dtype,
- org_arg, declaration_name):
- if self.entry.anon_struct_union and dtype == "" and param == "}":
- return # Ignore the ending }; from anonymous struct/union
-
- self.entry.anon_struct_union = False
-
- param = Re(r'[\[\)].*').sub('', param, count=1)
-
- if dtype == "" and param.endswith("..."):
- if Re(r'\w\.\.\.$').search(param):
- # For named variable parameters of the form `x...`,
- # remove the dots
- param = param[:-3]
- else:
- # Handles unnamed variable parameters
- param = "..."
-
- if param not in self.entry.parameterdescs or \
- not self.entry.parameterdescs[param]:
-
- self.entry.parameterdescs[param] = "variable arguments"
-
- elif dtype == "" and (not param or param == "void"):
- param = "void"
- self.entry.parameterdescs[param] = "no arguments"
-
- elif dtype == "" and param in ["struct", "union"]:
- # Handle unnamed (anonymous) union or struct
- dtype = param
- param = "{unnamed_" + param + "}"
- self.entry.parameterdescs[param] = "anonymous\n"
- self.entry.anon_struct_union = True
-
- # Handle cache group enforcing variables: they do not need
- # to be described in header files
- elif "__cacheline_group" in param:
- # Ignore __cacheline_group_begin and __cacheline_group_end
- return
-
- # Warn if parameter has no description
- # (but ignore ones starting with # as these are not parameters
- # but inline preprocessor statements)
- if param not in self.entry.parameterdescs and not param.startswith("#"):
- self.entry.parameterdescs[param] = self.undescribed
-
- if self.show_warnings(dtype, declaration_name) and "." not in param:
- if decl_type == 'function':
- dname = f"{decl_type} parameter"
- else:
- dname = f"{decl_type} member"
-
- self.emit_warning(ln,
- f"{dname} '{param}' not described in '{declaration_name}'")
-
- # Strip spaces from param so that it is one continuous string on
- # parameterlist. This fixes a problem where check_sections()
- # cannot find a parameter like "addr[6 + 2]" because it actually
- # appears as "addr[6", "+", "2]" on the parameter list.
- # However, it's better to maintain the param string unchanged for
- # output, so just weaken the string compare in check_sections()
- # to ignore "[blah" in a parameter string.
-
- self.entry.parameterlist.append(param)
- org_arg = Re(r'\s\s+').sub(' ', org_arg)
- self.entry.parametertypes[param] = org_arg
-
- def save_struct_actual(self, actual):
- """
- Strip all spaces from the actual param so that it looks like
- one string item.
- """
-
- actual = Re(r'\s*').sub("", actual, count=1)
-
- self.entry.struct_actual += actual + " "
-
- def create_parameter_list(self, ln, decl_type, args, splitter, declaration_name):
-
- # temporarily replace all commas inside function pointer definition
- arg_expr = Re(r'(\([^\),]+),')
- while arg_expr.search(args):
- args = arg_expr.sub(r"\1#", args)
-
- for arg in args.split(splitter):
- # Strip comments
- arg = Re(r'\/\*.*\*\/').sub('', arg)
-
- # Ignore argument attributes
- arg = Re(r'\sPOS0?\s').sub(' ', arg)
-
- # Strip leading/trailing spaces
- arg = arg.strip()
- arg = Re(r'\s+').sub(' ', arg, count=1)
-
- if arg.startswith('#'):
- # Treat preprocessor directive as a typeless variable just to fill
- # corresponding data structures "correctly". Catch it later in
- # output_* subs.
-
- # Treat preprocessor directive as a typeless variable
- self.push_parameter(ln, decl_type, arg, "",
- "", declaration_name)
-
- elif Re(r'\(.+\)\s*\(').search(arg):
- # Pointer-to-function
-
- arg = arg.replace('#', ',')
-
- r = Re(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)')
- if r.match(arg):
- param = r.group(1)
- else:
- self.emit_warning(ln, f"Invalid param: {arg}")
- param = arg
-
- dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
- self.save_struct_actual(param)
- self.push_parameter(ln, decl_type, param, dtype,
- arg, declaration_name)
-
- elif Re(r'\(.+\)\s*\[').search(arg):
- # Array-of-pointers
-
- arg = arg.replace('#', ',')
- r = Re(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)')
- if r.match(arg):
- param = r.group(1)
- else:
- self.emit_warning(ln, f"Invalid param: {arg}")
- param = arg
-
- dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
-
- self.save_struct_actual(param)
- self.push_parameter(ln, decl_type, param, dtype,
- arg, declaration_name)
-
- elif arg:
- arg = Re(r'\s*:\s*').sub(":", arg)
- arg = Re(r'\s*\[').sub('[', arg)
-
- args = Re(r'\s*,\s*').split(arg)
- if args[0] and '*' in args[0]:
- args[0] = re.sub(r'(\*+)\s*', r' \1', args[0])
-
- first_arg = []
- r = Re(r'^(.*\s+)(.*?\[.*\].*)$')
- if args[0] and r.match(args[0]):
- args.pop(0)
- first_arg.extend(r.group(1))
- first_arg.append(r.group(2))
- else:
- first_arg = Re(r'\s+').split(args.pop(0))
-
- args.insert(0, first_arg.pop())
- dtype = ' '.join(first_arg)
-
- for param in args:
- if Re(r'^(\*+)\s*(.*)').match(param):
- r = Re(r'^(\*+)\s*(.*)')
- if not r.match(param):
- self.emit_warning(ln, f"Invalid param: {param}")
- continue
-
- param = r.group(1)
-
- self.save_struct_actual(r.group(2))
- self.push_parameter(ln, decl_type, r.group(2),
- f"{dtype} {r.group(1)}",
- arg, declaration_name)
-
- elif Re(r'(.*?):(\w+)').search(param):
- r = Re(r'(.*?):(\w+)')
- if not r.match(param):
- self.emit_warning(ln, f"Invalid param: {param}")
- continue
-
- if dtype != "": # Skip unnamed bit-fields
- self.save_struct_actual(r.group(1))
- self.push_parameter(ln, decl_type, r.group(1),
- f"{dtype}:{r.group(2)}",
- arg, declaration_name)
- else:
- self.save_struct_actual(param)
- self.push_parameter(ln, decl_type, param, dtype,
- arg, declaration_name)
-
- def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck):
- sects = sectcheck.split()
- prms = prmscheck.split()
- err = False
-
- for sx in range(len(sects)): # pylint: disable=C0200
- err = True
- for px in range(len(prms)): # pylint: disable=C0200
- prm_clean = prms[px]
- prm_clean = Re(r'\[.*\]').sub('', prm_clean)
- prm_clean = attribute.sub('', prm_clean)
-
- # ignore array size in a parameter string;
- # however, the original param string may contain
- # spaces, e.g.: addr[6 + 2]
- # and this appears in @prms as "addr[6" since the
- # parameter list is split at spaces;
- # hence just ignore "[..." for the sections check;
- prm_clean = Re(r'\[.*').sub('', prm_clean)
-
- if prm_clean == sects[sx]:
- err = False
- break
-
- if err:
- if decl_type == 'function':
- dname = f"{decl_type} parameter"
- else:
- dname = f"{decl_type} member"
-
- self.emit_warning(ln,
- f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
-
- def check_return_section(self, ln, declaration_name, return_type):
-
- if not self.config.wreturn:
- return
-
- # Ignore an empty return type (It's a macro)
- # Ignore functions with a "void" return type (but not "void *")
- if not return_type or Re(r'void\s*\w*\s*$').search(return_type):
- return
-
- if not self.entry.sections.get("Return", None):
- self.emit_warning(ln,
- f"No description found for return value of '{declaration_name}'")
-
- def dump_struct(self, ln, proto):
- """
- Store an entry for an struct or union
- """
-
- type_pattern = r'(struct|union)'
-
- qualifiers = [
- "__attribute__",
- "__packed",
- "__aligned",
- "____cacheline_aligned_in_smp",
- "____cacheline_aligned",
- ]
-
- definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?"
- struct_members = Re(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)')
-
- # Extract struct/union definition
- members = None
- declaration_name = None
- decl_type = None
-
- r = Re(type_pattern + r'\s+(\w+)\s*' + definition_body)
- if r.search(proto):
- decl_type = r.group(1)
- declaration_name = r.group(2)
- members = r.group(3)
- else:
- r = Re(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;')
-
- if r.search(proto):
- decl_type = r.group(1)
- declaration_name = r.group(3)
- members = r.group(2)
-
- if not members:
- self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
- self.config.errors += 1
- return
-
- if self.entry.identifier != declaration_name:
- self.emit_warning(ln,
- f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
- return
-
- args_pattern =r'([^,)]+)'
-
- sub_prefixes = [
- (Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''),
- (Re(r'\/\*\s*private:.*', re.S| re.I), ''),
-
- # Strip comments
- (Re(r'\/\*.*?\*\/', re.S), ''),
-
- # Strip attributes
- (attribute, ' '),
- (Re(r'\s*__aligned\s*\([^;]*\)', re.S), ' '),
- (Re(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '),
- (Re(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '),
- (Re(r'\s*__packed\s*', re.S), ' '),
- (Re(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '),
- (Re(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
- (Re(r'\s*____cacheline_aligned', re.S), ' '),
-
- # Unwrap struct_group macros based on this definition:
- # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
- # which has variants like: struct_group(NAME, MEMBERS...)
- # Only MEMBERS arguments require documentation.
- #
- # Parsing them happens on two steps:
- #
- # 1. drop struct group arguments that aren't at MEMBERS,
- # storing them as STRUCT_GROUP(MEMBERS)
- #
- # 2. remove STRUCT_GROUP() ancillary macro.
- #
- # The original logic used to remove STRUCT_GROUP() using an
- # advanced regex:
- #
- # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;
- #
- # with two patterns that are incompatible with
- # Python re module, as it has:
- #
- # - a recursive pattern: (?1)
- # - an atomic grouping: (?>...)
- #
- # I tried a simpler version: but it didn't work either:
- # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*;
- #
- # As it doesn't properly match the end parenthesis on some cases.
- #
- # So, a better solution was crafted: there's now a NestedMatch
- # class that ensures that delimiters after a search are properly
- # matched. So, the implementation to drop STRUCT_GROUP() will be
- # handled in separate.
-
- (Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
- (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
- (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
- (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
-
- # Replace macros
- #
- # TODO: it is better to also move those to the NestedMatch logic,
- # to ensure that parenthesis will be properly matched.
-
- (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
- (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
- (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
- (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
- (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
- (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
- (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'),
- (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'),
- (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),
- ]
-
- # Regexes here are guaranteed to have the end limiter matching
- # the start delimiter. Yet, right now, only one replace group
- # is allowed.
-
- sub_nested_prefixes = [
- (re.compile(r'\bSTRUCT_GROUP\('), r'\1'),
- ]
-
- for search, sub in sub_prefixes:
- members = search.sub(sub, members)
-
- nested = NestedMatch()
-
- for search, sub in sub_nested_prefixes:
- members = nested.sub(search, sub, members)
-
- # Keeps the original declaration as-is
- declaration = members
-
- # Split nested struct/union elements
- #
- # This loop was simpler at the original kernel-doc perl version, as
- # while ($members =~ m/$struct_members/) { ... }
- # reads 'members' string on each interaction.
- #
- # Python behavior is different: it parses 'members' only once,
- # creating a list of tuples from the first interaction.
- #
- # On other words, this won't get nested structs.
- #
- # So, we need to have an extra loop on Python to override such
- # re limitation.
-
- while True:
- tuples = struct_members.findall(members)
- if not tuples:
- break
-
- for t in tuples:
- newmember = ""
- maintype = t[0]
- s_ids = t[5]
- content = t[3]
-
- oldmember = "".join(t)
-
- for s_id in s_ids.split(','):
- s_id = s_id.strip()
-
- newmember += f"{maintype} {s_id}; "
- s_id = Re(r'[:\[].*').sub('', s_id)
- s_id = Re(r'^\s*\**(\S+)\s*').sub(r'\1', s_id)
-
- for arg in content.split(';'):
- arg = arg.strip()
-
- if not arg:
- continue
-
- r = Re(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)')
- if r.match(arg):
- # Pointer-to-function
- dtype = r.group(1)
- name = r.group(2)
- extra = r.group(3)
-
- if not name:
- continue
-
- if not s_id:
- # Anonymous struct/union
- newmember += f"{dtype}{name}{extra}; "
- else:
- newmember += f"{dtype}{s_id}.{name}{extra}; "
-
- else:
- arg = arg.strip()
- # Handle bitmaps
- arg = Re(r':\s*\d+\s*').sub('', arg)
-
- # Handle arrays
- arg = Re(r'\[.*\]').sub('', arg)
-
- # Handle multiple IDs
- arg = Re(r'\s*,\s*').sub(',', arg)
-
-
- r = Re(r'(.*)\s+([\S+,]+)')
-
- if r.search(arg):
- dtype = r.group(1)
- names = r.group(2)
- else:
- newmember += f"{arg}; "
- continue
-
- for name in names.split(','):
- name = Re(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip()
-
- if not name:
- continue
-
- if not s_id:
- # Anonymous struct/union
- newmember += f"{dtype} {name}; "
- else:
- newmember += f"{dtype} {s_id}.{name}; "
-
- members = members.replace(oldmember, newmember)
-
- # Ignore other nested elements, like enums
- members = re.sub(r'(\{[^\{\}]*\})', '', members)
-
- self.create_parameter_list(ln, decl_type, members, ';',
- declaration_name)
- self.check_sections(ln, declaration_name, decl_type,
- self.entry.sectcheck, self.entry.struct_actual)
-
- # Adjust declaration for better display
- declaration = Re(r'([\{;])').sub(r'\1\n', declaration)
- declaration = Re(r'\}\s+;').sub('};', declaration)
-
- # Better handle inlined enums
- while True:
- r = Re(r'(enum\s+\{[^\}]+),([^\n])')
- if not r.search(declaration):
- break
-
- declaration = r.sub(r'\1,\n\2', declaration)
-
- def_args = declaration.split('\n')
- level = 1
- declaration = ""
- for clause in def_args:
-
- clause = clause.strip()
- clause = Re(r'\s+').sub(' ', clause, count=1)
-
- if not clause:
- continue
-
- if '}' in clause and level > 1:
- level -= 1
-
- if not Re(r'^\s*#').match(clause):
- declaration += "\t" * level
-
- declaration += "\t" + clause + "\n"
- if "{" in clause and "}" not in clause:
- level += 1
-
- self.output_declaration(decl_type, declaration_name,
- struct=declaration_name,
- module=self.entry.modulename,
- definition=declaration,
- parameterlist=self.entry.parameterlist,
- parameterdescs=self.entry.parameterdescs,
- parametertypes=self.entry.parametertypes,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections,
- purpose=self.entry.declaration_purpose)
-
- def dump_enum(self, ln, proto):
-
- # Ignore members marked private
- proto = Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto)
- proto = Re(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto)
-
- # Strip comments
- proto = Re(r'\/\*.*?\*\/', flags=re.S).sub('', proto)
-
- # Strip #define macros inside enums
- proto = Re(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto)
-
- members = None
- declaration_name = None
-
- r = Re(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;')
- if r.search(proto):
- declaration_name = r.group(2)
- members = r.group(1).rstrip()
- else:
- r = Re(r'enum\s+(\w*)\s*\{(.*)\}')
- if r.match(proto):
- declaration_name = r.group(1)
- members = r.group(2).rstrip()
-
- if not members:
- self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
- self.config.errors += 1
- return
-
- if self.entry.identifier != declaration_name:
- if self.entry.identifier == "":
- self.emit_warning(ln,
- f"{proto}: wrong kernel-doc identifier on prototype")
- else:
- self.emit_warning(ln,
- f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
- return
-
- if not declaration_name:
- declaration_name = "(anonymous)"
-
- member_set = set()
-
- members = Re(r'\([^;]*?[\)]').sub('', members)
-
- for arg in members.split(','):
- if not arg:
- continue
- arg = Re(r'^\s*(\w+).*').sub(r'\1', arg)
- self.entry.parameterlist.append(arg)
- if arg not in self.entry.parameterdescs:
- self.entry.parameterdescs[arg] = self.undescribed
- if self.show_warnings("enum", declaration_name):
- self.emit_warning(ln,
- f"Enum value '{arg}' not described in enum '{declaration_name}'")
- member_set.add(arg)
-
- for k in self.entry.parameterdescs:
- if k not in member_set:
- if self.show_warnings("enum", declaration_name):
- self.emit_warning(ln,
- f"Excess enum value '%{k}' description in '{declaration_name}'")
-
- self.output_declaration('enum', declaration_name,
- enum=declaration_name,
- module=self.config.modulename,
- parameterlist=self.entry.parameterlist,
- parameterdescs=self.entry.parameterdescs,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections,
- purpose=self.entry.declaration_purpose)
-
- def dump_declaration(self, ln, prototype):
- if self.entry.decl_type == "enum":
- self.dump_enum(ln, prototype)
- return
-
- if self.entry.decl_type == "typedef":
- self.dump_typedef(ln, prototype)
- return
-
- if self.entry.decl_type in ["union", "struct"]:
- self.dump_struct(ln, prototype)
- return
-
- # TODO: handle other types
- self.output_declaration(self.entry.decl_type, prototype,
- entry=self.entry)
-
- def dump_function(self, ln, prototype):
-
- func_macro = False
- return_type = ''
- decl_type = 'function'
-
- # Prefixes that would be removed
- sub_prefixes = [
- (r"^static +", "", 0),
- (r"^extern +", "", 0),
- (r"^asmlinkage +", "", 0),
- (r"^inline +", "", 0),
- (r"^__inline__ +", "", 0),
- (r"^__inline +", "", 0),
- (r"^__always_inline +", "", 0),
- (r"^noinline +", "", 0),
- (r"^__FORTIFY_INLINE +", "", 0),
- (r"__init +", "", 0),
- (r"__init_or_module +", "", 0),
- (r"__deprecated +", "", 0),
- (r"__flatten +", "", 0),
- (r"__meminit +", "", 0),
- (r"__must_check +", "", 0),
- (r"__weak +", "", 0),
- (r"__sched +", "", 0),
- (r"_noprof", "", 0),
- (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0),
- (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0),
- (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0),
- (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0),
- (r"__attribute_const__ +", "", 0),
-
- # It seems that Python support for re.X is broken:
- # At least for me (Python 3.13), this didn't work
-# (r"""
-# __attribute__\s*\(\(
-# (?:
-# [\w\s]+ # attribute name
-# (?:\([^)]*\))? # attribute arguments
-# \s*,? # optional comma at the end
-# )+
-# \)\)\s+
-# """, "", re.X),
-
- # So, remove whitespaces and comments from it
- (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0),
- ]
-
- for search, sub, flags in sub_prefixes:
- prototype = Re(search, flags).sub(sub, prototype)
-
- # Macros are a special case, as they change the prototype format
- new_proto = Re(r"^#\s*define\s+").sub("", prototype)
- if new_proto != prototype:
- is_define_proto = True
- prototype = new_proto
- else:
- is_define_proto = False
-
- # Yes, this truly is vile. We are looking for:
- # 1. Return type (may be nothing if we're looking at a macro)
- # 2. Function name
- # 3. Function parameters.
- #
- # All the while we have to watch out for function pointer parameters
- # (which IIRC is what the two sections are for), C types (these
- # regexps don't even start to express all the possibilities), and
- # so on.
- #
- # If you mess with these regexps, it's a good idea to check that
- # the following functions' documentation still comes out right:
- # - parport_register_device (function pointer parameters)
- # - atomic_set (macro)
- # - pci_match_device, __copy_to_user (long return type)
-
- name = r'[a-zA-Z0-9_~:]+'
- prototype_end1 = r'[^\(]*'
- prototype_end2 = r'[^\{]*'
- prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)'
-
- # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group.
- # So, this needs to be mapped in Python with (?:...)? or (?:...)+
-
- type1 = r'(?:[\w\s]+)?'
- type2 = r'(?:[\w\s]+\*+)+'
-
- found = False
-
- if is_define_proto:
- r = Re(r'^()(' + name + r')\s+')
-
- if r.search(prototype):
- return_type = ''
- declaration_name = r.group(2)
- func_macro = True
-
- found = True
-
- if not found:
- patterns = [
- rf'^()({name})\s*{prototype_end}',
- rf'^({type1})\s+({name})\s*{prototype_end}',
- rf'^({type2})\s*({name})\s*{prototype_end}',
- ]
-
- for p in patterns:
- r = Re(p)
-
- if r.match(prototype):
-
- return_type = r.group(1)
- declaration_name = r.group(2)
- args = r.group(3)
-
- self.create_parameter_list(ln, decl_type, args, ',',
- declaration_name)
-
- found = True
- break
- if not found:
- self.emit_warning(ln,
- f"cannot understand function prototype: '{prototype}'")
- return
-
- if self.entry.identifier != declaration_name:
- self.emit_warning(ln,
- f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
- return
-
- prms = " ".join(self.entry.parameterlist)
- self.check_sections(ln, declaration_name, "function",
- self.entry.sectcheck, prms)
-
- self.check_return_section(ln, declaration_name, return_type)
-
- if 'typedef' in return_type:
- self.output_declaration(decl_type, declaration_name,
- function=declaration_name,
- typedef=True,
- module=self.config.modulename,
- functiontype=return_type,
- parameterlist=self.entry.parameterlist,
- parameterdescs=self.entry.parameterdescs,
- parametertypes=self.entry.parametertypes,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections,
- purpose=self.entry.declaration_purpose,
- func_macro=func_macro)
- else:
- self.output_declaration(decl_type, declaration_name,
- function=declaration_name,
- typedef=False,
- module=self.config.modulename,
- functiontype=return_type,
- parameterlist=self.entry.parameterlist,
- parameterdescs=self.entry.parameterdescs,
- parametertypes=self.entry.parametertypes,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections,
- purpose=self.entry.declaration_purpose,
- func_macro=func_macro)
-
- def dump_typedef(self, ln, proto):
- typedef_type = r'((?:\s+[\w\*]+\b){1,8})\s*'
- typedef_ident = r'\*?\s*(\w\S+)\s*'
- typedef_args = r'\s*\((.*)\);'
-
- typedef1 = Re(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args)
- typedef2 = Re(r'typedef' + typedef_type + typedef_ident + typedef_args)
-
- # Strip comments
- proto = Re(r'/\*.*?\*/', flags=re.S).sub('', proto)
-
- # Parse function typedef prototypes
- for r in [typedef1, typedef2]:
- if not r.match(proto):
- continue
-
- return_type = r.group(1).strip()
- declaration_name = r.group(2)
- args = r.group(3)
-
- if self.entry.identifier != declaration_name:
- self.emit_warning(ln,
- f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
- return
-
- decl_type = 'function'
- self.create_parameter_list(ln, decl_type, args, ',', declaration_name)
-
- self.output_declaration(decl_type, declaration_name,
- function=declaration_name,
- typedef=True,
- module=self.entry.modulename,
- functiontype=return_type,
- parameterlist=self.entry.parameterlist,
- parameterdescs=self.entry.parameterdescs,
- parametertypes=self.entry.parametertypes,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections,
- purpose=self.entry.declaration_purpose)
- return
-
- # Handle nested parentheses or brackets
- r = Re(r'(\(*.\)\s*|\[*.\]\s*);$')
- while r.search(proto):
- proto = r.sub('', proto)
-
- # Parse simple typedefs
- r = Re(r'typedef.*\s+(\w+)\s*;')
- if r.match(proto):
- declaration_name = r.group(1)
-
- if self.entry.identifier != declaration_name:
- self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
- return
-
- self.output_declaration('typedef', declaration_name,
- typedef=declaration_name,
- module=self.entry.modulename,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections,
- purpose=self.entry.declaration_purpose)
- return
-
- self.emit_warning(ln, "error: Cannot parse typedef!")
- self.config.errors += 1
-
- @staticmethod
- def process_export(function_table, line):
- """
- process EXPORT_SYMBOL* tags
-
- This method is called both internally and externally, so, it
- doesn't use self.
- """
-
- if export_symbol.search(line):
- symbol = export_symbol.group(2)
- function_table.add(symbol)
-
- if export_symbol_ns.search(line):
- symbol = export_symbol_ns.group(2)
- function_table.add(symbol)
-
- def process_normal(self, ln, line):
- """
- STATE_NORMAL: looking for the /** to begin everything.
- """
-
- if not doc_start.match(line):
- return
-
- # start a new entry
- self.reset_state(ln + 1)
- self.entry.in_doc_sect = False
-
- # next line is always the function name
- self.state = self.STATE_NAME
-
- def process_name(self, ln, line):
- """
- STATE_NAME: Looking for the "name - description" line
- """
-
- if doc_block.search(line):
- self.entry.new_start_line = ln
-
- if not doc_block.group(1):
- self.entry.section = self.section_intro
- else:
- self.entry.section = doc_block.group(1)
-
- self.state = self.STATE_DOCBLOCK
- return
-
- if doc_decl.search(line):
- self.entry.identifier = doc_decl.group(1)
- self.entry.is_kernel_comment = False
-
- decl_start = str(doc_com) # comment block asterisk
- fn_type = r"(?:\w+\s*\*\s*)?" # type (for non-functions)
- parenthesis = r"(?:\(\w*\))?" # optional parenthesis on function
- decl_end = r"(?:[-:].*)" # end of the name part
-
- # test for pointer declaration type, foo * bar() - desc
- r = Re(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$")
- if r.search(line):
- self.entry.identifier = r.group(1)
-
- # Test for data declaration
- r = Re(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)")
- if r.search(line):
- self.entry.decl_type = r.group(1)
- self.entry.identifier = r.group(2)
- self.entry.is_kernel_comment = True
- else:
- # Look for foo() or static void foo() - description;
- # or misspelt identifier
-
- r1 = Re(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$")
- r2 = Re(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$")
-
- for r in [r1, r2]:
- if r.search(line):
- self.entry.identifier = r.group(1)
- self.entry.decl_type = "function"
-
- r = Re(r"define\s+")
- self.entry.identifier = r.sub("", self.entry.identifier)
- self.entry.is_kernel_comment = True
- break
-
- self.entry.identifier = self.entry.identifier.strip(" ")
-
- self.state = self.STATE_BODY
-
- # if there's no @param blocks need to set up default section here
- self.entry.section = self.section_default
- self.entry.new_start_line = ln + 1
-
- r = Re("[-:](.*)")
- if r.search(line):
- # strip leading/trailing/multiple spaces
- self.entry.descr = r.group(1).strip(" ")
-
- r = Re(r"\s+")
- self.entry.descr = r.sub(" ", self.entry.descr)
- self.entry.declaration_purpose = self.entry.descr
- self.state = self.STATE_BODY_MAYBE
- else:
- self.entry.declaration_purpose = ""
-
- if not self.entry.is_kernel_comment:
- self.emit_warning(ln,
- f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
- self.state = self.STATE_NORMAL
-
- if not self.entry.declaration_purpose and self.config.wshort_desc:
- self.emit_warning(ln,
- f"missing initial short description on line:\n{line}")
-
- if not self.entry.identifier and self.entry.decl_type != "enum":
- self.emit_warning(ln,
- f"wrong kernel-doc identifier on line:\n{line}")
- self.state = self.STATE_NORMAL
-
- if self.config.verbose:
- self.emit_warning(ln,
- f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
- warning=False)
-
- return
-
- # Failed to find an identifier. Emit a warning
- self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
-
- def process_body(self, ln, line):
- """
- STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.
- """
-
- if self.state == self.STATE_BODY_WITH_BLANK_LINE:
- r = Re(r"\s*\*\s?\S")
- if r.match(line):
- self.dump_section()
- self.entry.section = self.section_default
- self.entry.new_start_line = line
- self.entry.contents = ""
-
- if doc_sect.search(line):
- self.entry.in_doc_sect = True
- newsection = doc_sect.group(1)
-
- if newsection.lower() in ["description", "context"]:
- newsection = newsection.title()
-
- # Special case: @return is a section, not a param description
- if newsection.lower() in ["@return", "@returns",
- "return", "returns"]:
- newsection = "Return"
-
- # Perl kernel-doc has a check here for contents before sections.
- # the logic there is always false, as in_doc_sect variable is
- # always true. So, just don't implement Wcontents_before_sections
-
- # .title()
- newcontents = doc_sect.group(2)
- if not newcontents:
- newcontents = ""
-
- if self.entry.contents.strip("\n"):
- self.dump_section()
-
- self.entry.new_start_line = ln
- self.entry.section = newsection
- self.entry.leading_space = None
-
- self.entry.contents = newcontents.lstrip()
- if self.entry.contents:
- self.entry.contents += "\n"
-
- self.state = self.STATE_BODY
- return
-
- if doc_end.search(line):
- self.dump_section()
-
- # Look for doc_com + <text> + doc_end:
- r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
- if r.match(line):
- self.emit_warning(ln, f"suspicious ending line: {line}")
-
- self.entry.prototype = ""
- self.entry.new_start_line = ln + 1
-
- self.state = self.STATE_PROTO
- return
-
- if doc_content.search(line):
- cont = doc_content.group(1)
-
- if cont == "":
- if self.entry.section == self.section_context:
- self.dump_section()
-
- self.entry.new_start_line = ln
- self.state = self.STATE_BODY
- else:
- if self.entry.section != self.section_default:
- self.state = self.STATE_BODY_WITH_BLANK_LINE
- else:
- self.state = self.STATE_BODY
-
- self.entry.contents += "\n"
-
- elif self.state == self.STATE_BODY_MAYBE:
-
- # Continued declaration purpose
- self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip()
- self.entry.declaration_purpose += " " + cont
-
- r = Re(r"\s+")
- self.entry.declaration_purpose = r.sub(' ',
- self.entry.declaration_purpose)
-
- else:
- if self.entry.section.startswith('@') or \
- self.entry.section == self.section_context:
- if self.entry.leading_space is None:
- r = Re(r'^(\s+)')
- if r.match(cont):
- self.entry.leading_space = len(r.group(1))
- else:
- self.entry.leading_space = 0
-
- # Double-check if leading space are realy spaces
- pos = 0
- for i in range(0, self.entry.leading_space):
- if cont[i] != " ":
- break
- pos += 1
-
- cont = cont[pos:]
-
- # NEW LOGIC:
- # In case it is different, update it
- if self.entry.leading_space != pos:
- self.entry.leading_space = pos
-
- self.entry.contents += cont + "\n"
- return
-
- # Unknown line, ignore
- self.emit_warning(ln, f"bad line: {line}")
-
- def process_inline(self, ln, line):
- """STATE_INLINE: docbook comments within a prototype."""
-
- if self.inline_doc_state == self.STATE_INLINE_NAME and \
- doc_inline_sect.search(line):
- self.entry.section = doc_inline_sect.group(1)
- self.entry.new_start_line = ln
-
- self.entry.contents = doc_inline_sect.group(2).lstrip()
- if self.entry.contents != "":
- self.entry.contents += "\n"
-
- self.inline_doc_state = self.STATE_INLINE_TEXT
- # Documentation block end */
- return
-
- if doc_inline_end.search(line):
- if self.entry.contents not in ["", "\n"]:
- self.dump_section()
-
- self.state = self.STATE_PROTO
- self.inline_doc_state = self.STATE_INLINE_NA
- return
-
- if doc_content.search(line):
- if self.inline_doc_state == self.STATE_INLINE_TEXT:
- self.entry.contents += doc_content.group(1) + "\n"
- if not self.entry.contents.strip(" ").rstrip("\n"):
- self.entry.contents = ""
-
- elif self.inline_doc_state == self.STATE_INLINE_NAME:
- self.emit_warning(ln,
- f"Incorrect use of kernel-doc format: {line}")
-
- self.inline_doc_state = self.STATE_INLINE_ERROR
-
- def syscall_munge(self, ln, proto):
- """
- Handle syscall definitions
- """
-
- is_void = False
-
- # Strip newlines/CR's
- proto = re.sub(r'[\r\n]+', ' ', proto)
-
- # Check if it's a SYSCALL_DEFINE0
- if 'SYSCALL_DEFINE0' in proto:
- is_void = True
-
- # Replace SYSCALL_DEFINE with correct return type & function name
- proto = Re(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
-
- r = Re(r'long\s+(sys_.*?),')
- if r.search(proto):
- proto = proto.replace(',', '(', count=1)
- elif is_void:
- proto = proto.replace(')', '(void)', count=1)
-
- # Now delete all of the odd-numbered commas in the proto
- # so that argument types & names don't have a comma between them
- count = 0
- length = len(proto)
-
- if is_void:
- length = 0 # skip the loop if is_void
-
- for ix in range(length):
- if proto[ix] == ',':
- count += 1
- if count % 2 == 1:
- proto = proto[:ix] + ' ' + proto[ix+1:]
-
- return proto
-
- def tracepoint_munge(self, ln, proto):
- """
- Handle tracepoint definitions
- """
-
- tracepointname = None
- tracepointargs = None
-
- # Match tracepoint name based on different patterns
- r = Re(r'TRACE_EVENT\((.*?),')
- if r.search(proto):
- tracepointname = r.group(1)
-
- r = Re(r'DEFINE_SINGLE_EVENT\((.*?),')
- if r.search(proto):
- tracepointname = r.group(1)
-
- r = Re(r'DEFINE_EVENT\((.*?),(.*?),')
- if r.search(proto):
- tracepointname = r.group(2)
-
- if tracepointname:
- tracepointname = tracepointname.lstrip()
-
- r = Re(r'TP_PROTO\((.*?)\)')
- if r.search(proto):
- tracepointargs = r.group(1)
-
- if not tracepointname or not tracepointargs:
- self.emit_warning(ln,
- f"Unrecognized tracepoint format:\n{proto}\n")
- else:
- proto = f"static inline void trace_{tracepointname}({tracepointargs})"
- self.entry.identifier = f"trace_{self.entry.identifier}"
-
- return proto
-
- def process_proto_function(self, ln, line):
- """Ancillary routine to process a function prototype"""
-
- # strip C99-style comments to end of line
- r = Re(r"\/\/.*$", re.S)
- line = r.sub('', line)
-
- if Re(r'\s*#\s*define').match(line):
- self.entry.prototype = line
- elif line.startswith('#'):
- # Strip other macros like #ifdef/#ifndef/#endif/...
- pass
- else:
- r = Re(r'([^\{]*)')
- if r.match(line):
- self.entry.prototype += r.group(1) + " "
-
- if '{' in line or ';' in line or Re(r'\s*#\s*define').match(line):
- # strip comments
- r = Re(r'/\*.*?\*/')
- self.entry.prototype = r.sub('', self.entry.prototype)
-
- # strip newlines/cr's
- r = Re(r'[\r\n]+')
- self.entry.prototype = r.sub(' ', self.entry.prototype)
-
- # strip leading spaces
- r = Re(r'^\s+')
- self.entry.prototype = r.sub('', self.entry.prototype)
-
- # Handle self.entry.prototypes for function pointers like:
- # int (*pcs_config)(struct foo)
-
- r = Re(r'^(\S+\s+)\(\s*\*(\S+)\)')
- self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
-
- if 'SYSCALL_DEFINE' in self.entry.prototype:
- self.entry.prototype = self.syscall_munge(ln,
- self.entry.prototype)
-
- r = Re(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
- if r.search(self.entry.prototype):
- self.entry.prototype = self.tracepoint_munge(ln,
- self.entry.prototype)
-
- self.dump_function(ln, self.entry.prototype)
- self.reset_state(ln)
-
- def process_proto_type(self, ln, line):
- """Ancillary routine to process a type"""
-
- # Strip newlines/cr's.
- line = Re(r'[\r\n]+', re.S).sub(' ', line)
-
- # Strip leading spaces
- line = Re(r'^\s+', re.S).sub('', line)
-
- # Strip trailing spaces
- line = Re(r'\s+$', re.S).sub('', line)
-
- # Strip C99-style comments to the end of the line
- line = Re(r"\/\/.*$", re.S).sub('', line)
-
- # To distinguish preprocessor directive from regular declaration later.
- if line.startswith('#'):
- line += ";"
-
- r = Re(r'([^\{\};]*)([\{\};])(.*)')
- while True:
- if r.search(line):
- if self.entry.prototype:
- self.entry.prototype += " "
- self.entry.prototype += r.group(1) + r.group(2)
-
- self.entry.brcount += r.group(2).count('{')
- self.entry.brcount -= r.group(2).count('}')
-
- self.entry.brcount = max(self.entry.brcount, 0)
-
- if r.group(2) == ';' and self.entry.brcount == 0:
- self.dump_declaration(ln, self.entry.prototype)
- self.reset_state(ln)
- break
-
- line = r.group(3)
- else:
- self.entry.prototype += line
- break
-
- def process_proto(self, ln, line):
- """STATE_PROTO: reading a function/whatever prototype."""
-
- if doc_inline_oneline.search(line):
- self.entry.section = doc_inline_oneline.group(1)
- self.entry.contents = doc_inline_oneline.group(2)
-
- if self.entry.contents != "":
- self.entry.contents += "\n"
- self.dump_section(start_new=False)
-
- elif doc_inline_start.search(line):
- self.state = self.STATE_INLINE
- self.inline_doc_state = self.STATE_INLINE_NAME
-
- elif self.entry.decl_type == 'function':
- self.process_proto_function(ln, line)
-
- else:
- self.process_proto_type(ln, line)
-
- def process_docblock(self, ln, line):
- """STATE_DOCBLOCK: within a DOC: block."""
-
- if doc_end.search(line):
- self.dump_section()
- self.output_declaration("doc", None,
- sectionlist=self.entry.sectionlist,
- sections=self.entry.sections, module=self.config.modulename)
- self.reset_state(ln)
-
- elif doc_content.search(line):
- self.entry.contents += doc_content.group(1) + "\n"
-
- def run(self):
- """
- Open and process each line of a C source file.
- he parsing is controlled via a state machine, and the line is passed
- to a different process function depending on the state. The process
- function may update the state as needed.
- """
-
- cont = False
- prev = ""
- prev_ln = None
-
- try:
- with open(self.fname, "r", encoding="utf8",
- errors="backslashreplace") as fp:
- for ln, line in enumerate(fp):
-
- line = line.expandtabs().strip("\n")
-
- # Group continuation lines on prototypes
- if self.state == self.STATE_PROTO:
- if line.endswith("\\"):
- prev += line.removesuffix("\\")
- cont = True
-
- if not prev_ln:
- prev_ln = ln
-
- continue
-
- if cont:
- ln = prev_ln
- line = prev + line
- prev = ""
- cont = False
- prev_ln = None
-
- self.config.log.debug("%d %s%s: %s",
- ln, self.st_name[self.state],
- self.st_inline_name[self.inline_doc_state],
- line)
-
- # TODO: not all states allow EXPORT_SYMBOL*, so this
- # can be optimized later on to speedup parsing
- self.process_export(self.config.function_table, line)
-
- # Hand this line to the appropriate state handler
- if self.state == self.STATE_NORMAL:
- self.process_normal(ln, line)
- elif self.state == self.STATE_NAME:
- self.process_name(ln, line)
- elif self.state in [self.STATE_BODY, self.STATE_BODY_MAYBE,
- self.STATE_BODY_WITH_BLANK_LINE]:
- self.process_body(ln, line)
- elif self.state == self.STATE_INLINE: # scanning for inline parameters
- self.process_inline(ln, line)
- elif self.state == self.STATE_PROTO:
- self.process_proto(ln, line)
- elif self.state == self.STATE_DOCBLOCK:
- self.process_docblock(ln, line)
- except OSError:
- self.config.log.error(f"Error: Cannot open file {self.fname}")
- self.config.errors += 1
-
-
class GlobSourceFiles:
"""
Parse C source code file names and directories via an Interactor.
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
new file mode 100755
index 000000000000..6d6395e32093
--- /dev/null
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -0,0 +1,1689 @@
+#!/usr/bin/env python3
+# pylint: disable=C0301,C0302,R0904,R0912,R0913,R0914,R0915,R0917,R1702
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+kdoc_parser
+===========
+
+Read a C language source or header FILE and extract embedded
+documentation comments
+"""
+
+import argparse
+import re
+from pprint import pformat
+
+from kdoc_re import NestedMatch, Re
+
+
+#
+# Regular expressions used to parse kernel-doc markups at KernelDoc class.
+#
+# Let's declare them in lowercase outside any class to make easier to
+# convert from the python script.
+#
+# As those are evaluated at the beginning, no need to cache them
+#
+
+# Allow whitespace at end of comment start.
+doc_start = Re(r'^/\*\*\s*$', cache=False)
+
+doc_end = Re(r'\*/', cache=False)
+doc_com = Re(r'\s*\*\s*', cache=False)
+doc_com_body = Re(r'\s*\* ?', cache=False)
+doc_decl = doc_com + Re(r'(\w+)', cache=False)
+
+# @params and a strictly limited set of supported section names
+# Specifically:
+# Match @word:
+# @...:
+# @{section-name}:
+# while trying to not match literal block starts like "example::"
+#
+doc_sect = doc_com + \
+ Re(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$',
+ flags=re.I, cache=False)
+
+doc_content = doc_com_body + Re(r'(.*)', cache=False)
+doc_block = doc_com + Re(r'DOC:\s*(.*)?', cache=False)
+doc_inline_start = Re(r'^\s*/\*\*\s*$', cache=False)
+doc_inline_sect = Re(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False)
+doc_inline_end = Re(r'^\s*\*/\s*$', cache=False)
+doc_inline_oneline = Re(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False)
+attribute = Re(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)",
+ flags=re.I | re.S, cache=False)
+
+export_symbol = Re(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False)
+export_symbol_ns = Re(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False)
+
+type_param = Re(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+
+
+class KernelDoc:
+ """
+ Read a C language source or header FILE and extract embedded
+ documentation comments.
+ """
+
+ # Parser states
+ STATE_NORMAL = 0 # normal code
+ STATE_NAME = 1 # looking for function name
+ STATE_BODY_MAYBE = 2 # body - or maybe more description
+ STATE_BODY = 3 # the body of the comment
+ STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
+ STATE_PROTO = 5 # scanning prototype
+ STATE_DOCBLOCK = 6 # documentation block
+ STATE_INLINE = 7 # gathering doc outside main block
+
+ st_name = [
+ "NORMAL",
+ "NAME",
+ "BODY_MAYBE",
+ "BODY",
+ "BODY_WITH_BLANK_LINE",
+ "PROTO",
+ "DOCBLOCK",
+ "INLINE",
+ ]
+
+ # Inline documentation state
+ STATE_INLINE_NA = 0 # not applicable ($state != STATE_INLINE)
+ STATE_INLINE_NAME = 1 # looking for member name (@foo:)
+ STATE_INLINE_TEXT = 2 # looking for member documentation
+ STATE_INLINE_END = 3 # done
+ STATE_INLINE_ERROR = 4 # error - Comment without header was found.
+ # Spit a warning as it's not
+ # proper kernel-doc and ignore the rest.
+
+ st_inline_name = [
+ "",
+ "_NAME",
+ "_TEXT",
+ "_END",
+ "_ERROR",
+ ]
+
+ # Section names
+
+ section_default = "Description" # default section
+ section_intro = "Introduction"
+ section_context = "Context"
+ section_return = "Return"
+
+ undescribed = "-- undescribed --"
+
+ def __init__(self, config, fname):
+ """Initialize internal variables"""
+
+ self.fname = fname
+ self.config = config
+
+ # Initial state for the state machines
+ self.state = self.STATE_NORMAL
+ self.inline_doc_state = self.STATE_INLINE_NA
+
+ # Store entry currently being processed
+ self.entry = None
+
+ # Place all potential outputs into an array
+ self.entries = []
+
+ def show_warnings(self, dtype, declaration_name): # pylint: disable=W0613
+ """
+ Allow filtering out warnings
+ """
+
+ # TODO: implement it
+
+ return True
+
+ # TODO: rename to emit_message
+ def emit_warning(self, ln, msg, warning=True):
+ """Emit a message"""
+
+ if warning:
+ self.config.log.warning("%s:%d %s", self.fname, ln, msg)
+ else:
+ self.config.log.info("%s:%d %s", self.fname, ln, msg)
+
+ def dump_section(self, start_new=True):
+ """
+ Dumps section contents to arrays/hashes intended for that purpose.
+ """
+
+ name = self.entry.section
+ contents = self.entry.contents
+
+ # TODO: we can prevent dumping empty sections here with:
+ #
+ # if self.entry.contents.strip("\n"):
+ # if start_new:
+ # self.entry.section = self.section_default
+ # self.entry.contents = ""
+ #
+ # return
+ #
+ # But, as we want to be producing the same output of the
+ # venerable kernel-doc Perl tool, let's just output everything,
+ # at least for now
+
+ if type_param.match(name):
+ name = type_param.group(1)
+
+ self.entry.parameterdescs[name] = contents
+ self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+
+ self.entry.sectcheck += name + " "
+ self.entry.new_start_line = 0
+
+ elif name == "@...":
+ name = "..."
+ self.entry.parameterdescs[name] = contents
+ self.entry.sectcheck += name + " "
+ self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+ self.entry.new_start_line = 0
+
+ else:
+ if name in self.entry.sections and self.entry.sections[name] != "":
+ # Only warn on user-specified duplicate section names
+ if name != self.section_default:
+ self.emit_warning(self.entry.new_start_line,
+ f"duplicate section name '{name}'\n")
+ self.entry.sections[name] += contents
+ else:
+ self.entry.sections[name] = contents
+ self.entry.sectionlist.append(name)
+ self.entry.section_start_lines[name] = self.entry.new_start_line
+ self.entry.new_start_line = 0
+
+# self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
+
+ if start_new:
+ self.entry.section = self.section_default
+ self.entry.contents = ""
+
+ # TODO: rename it to store_declaration
+ def output_declaration(self, dtype, name, **args):
+ """
+ Stores the entry into an entry array.
+
+ The actual output and output filters will be handled elsewhere
+ """
+
+ # The implementation here is different than the original kernel-doc:
+ # instead of checking for output filters or actually output anything,
+ # it just stores the declaration content at self.entries, as the
+ # output will happen on a separate class.
+ #
+ # For now, we're keeping the same name of the function just to make
+ # easier to compare the source code of both scripts
+
+ if "declaration_start_line" not in args:
+ args["declaration_start_line"] = self.entry.declaration_start_line
+
+ args["type"] = dtype
+
+ # TODO: use colletions.OrderedDict
+
+ sections = args.get('sections', {})
+ sectionlist = args.get('sectionlist', [])
+
+ # Drop empty sections
+ # TODO: improve it to emit warnings
+ for section in ["Description", "Return"]:
+ if section in sectionlist:
+ if not sections[section].rstrip():
+ del sections[section]
+ sectionlist.remove(section)
+
+ self.entries.append((name, args))
+
+ self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
+
+ def reset_state(self, ln):
+ """
+ Ancillary routine to create a new entry. It initializes all
+ variables used by the state machine.
+ """
+
+ self.entry = argparse.Namespace
+
+ self.entry.contents = ""
+ self.entry.function = ""
+ self.entry.sectcheck = ""
+ self.entry.struct_actual = ""
+ self.entry.prototype = ""
+
+ self.entry.parameterlist = []
+ self.entry.parameterdescs = {}
+ self.entry.parametertypes = {}
+ self.entry.parameterdesc_start_lines = {}
+
+ self.entry.section_start_lines = {}
+ self.entry.sectionlist = []
+ self.entry.sections = {}
+
+ self.entry.anon_struct_union = False
+
+ self.entry.leading_space = None
+
+ # State flags
+ self.state = self.STATE_NORMAL
+ self.inline_doc_state = self.STATE_INLINE_NA
+ self.entry.brcount = 0
+
+ self.entry.in_doc_sect = False
+ self.entry.declaration_start_line = ln
+
+ def push_parameter(self, ln, decl_type, param, dtype,
+ org_arg, declaration_name):
+ """
+ Store parameters and their descriptions at self.entry.
+ """
+
+ if self.entry.anon_struct_union and dtype == "" and param == "}":
+ return # Ignore the ending }; from anonymous struct/union
+
+ self.entry.anon_struct_union = False
+
+ param = Re(r'[\[\)].*').sub('', param, count=1)
+
+ if dtype == "" and param.endswith("..."):
+ if Re(r'\w\.\.\.$').search(param):
+ # For named variable parameters of the form `x...`,
+ # remove the dots
+ param = param[:-3]
+ else:
+ # Handles unnamed variable parameters
+ param = "..."
+
+ if param not in self.entry.parameterdescs or \
+ not self.entry.parameterdescs[param]:
+
+ self.entry.parameterdescs[param] = "variable arguments"
+
+ elif dtype == "" and (not param or param == "void"):
+ param = "void"
+ self.entry.parameterdescs[param] = "no arguments"
+
+ elif dtype == "" and param in ["struct", "union"]:
+ # Handle unnamed (anonymous) union or struct
+ dtype = param
+ param = "{unnamed_" + param + "}"
+ self.entry.parameterdescs[param] = "anonymous\n"
+ self.entry.anon_struct_union = True
+
+ # Handle cache group enforcing variables: they do not need
+ # to be described in header files
+ elif "__cacheline_group" in param:
+ # Ignore __cacheline_group_begin and __cacheline_group_end
+ return
+
+ # Warn if parameter has no description
+ # (but ignore ones starting with # as these are not parameters
+ # but inline preprocessor statements)
+ if param not in self.entry.parameterdescs and not param.startswith("#"):
+ self.entry.parameterdescs[param] = self.undescribed
+
+ if self.show_warnings(dtype, declaration_name) and "." not in param:
+ if decl_type == 'function':
+ dname = f"{decl_type} parameter"
+ else:
+ dname = f"{decl_type} member"
+
+ self.emit_warning(ln,
+ f"{dname} '{param}' not described in '{declaration_name}'")
+
+ # Strip spaces from param so that it is one continuous string on
+ # parameterlist. This fixes a problem where check_sections()
+ # cannot find a parameter like "addr[6 + 2]" because it actually
+ # appears as "addr[6", "+", "2]" on the parameter list.
+ # However, it's better to maintain the param string unchanged for
+ # output, so just weaken the string compare in check_sections()
+ # to ignore "[blah" in a parameter string.
+
+ self.entry.parameterlist.append(param)
+ org_arg = Re(r'\s\s+').sub(' ', org_arg)
+ self.entry.parametertypes[param] = org_arg
+
+ def save_struct_actual(self, actual):
+ """
+ Strip all spaces from the actual param so that it looks like
+ one string item.
+ """
+
+ actual = Re(r'\s*').sub("", actual, count=1)
+
+ self.entry.struct_actual += actual + " "
+
+ def create_parameter_list(self, ln, decl_type, args,
+ splitter, declaration_name):
+ """
+ Creates a list of parameters, storing them at self.entry.
+ """
+
+ # temporarily replace all commas inside function pointer definition
+ arg_expr = Re(r'(\([^\),]+),')
+ while arg_expr.search(args):
+ args = arg_expr.sub(r"\1#", args)
+
+ for arg in args.split(splitter):
+ # Strip comments
+ arg = Re(r'\/\*.*\*\/').sub('', arg)
+
+ # Ignore argument attributes
+ arg = Re(r'\sPOS0?\s').sub(' ', arg)
+
+ # Strip leading/trailing spaces
+ arg = arg.strip()
+ arg = Re(r'\s+').sub(' ', arg, count=1)
+
+ if arg.startswith('#'):
+ # Treat preprocessor directive as a typeless variable just to fill
+ # corresponding data structures "correctly". Catch it later in
+ # output_* subs.
+
+ # Treat preprocessor directive as a typeless variable
+ self.push_parameter(ln, decl_type, arg, "",
+ "", declaration_name)
+
+ elif Re(r'\(.+\)\s*\(').search(arg):
+ # Pointer-to-function
+
+ arg = arg.replace('#', ',')
+
+ r = Re(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)')
+ if r.match(arg):
+ param = r.group(1)
+ else:
+ self.emit_warning(ln, f"Invalid param: {arg}")
+ param = arg
+
+ dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+ self.save_struct_actual(param)
+ self.push_parameter(ln, decl_type, param, dtype,
+ arg, declaration_name)
+
+ elif Re(r'\(.+\)\s*\[').search(arg):
+ # Array-of-pointers
+
+ arg = arg.replace('#', ',')
+ r = Re(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)')
+ if r.match(arg):
+ param = r.group(1)
+ else:
+ self.emit_warning(ln, f"Invalid param: {arg}")
+ param = arg
+
+ dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+
+ self.save_struct_actual(param)
+ self.push_parameter(ln, decl_type, param, dtype,
+ arg, declaration_name)
+
+ elif arg:
+ arg = Re(r'\s*:\s*').sub(":", arg)
+ arg = Re(r'\s*\[').sub('[', arg)
+
+ args = Re(r'\s*,\s*').split(arg)
+ if args[0] and '*' in args[0]:
+ args[0] = re.sub(r'(\*+)\s*', r' \1', args[0])
+
+ first_arg = []
+ r = Re(r'^(.*\s+)(.*?\[.*\].*)$')
+ if args[0] and r.match(args[0]):
+ args.pop(0)
+ first_arg.extend(r.group(1))
+ first_arg.append(r.group(2))
+ else:
+ first_arg = Re(r'\s+').split(args.pop(0))
+
+ args.insert(0, first_arg.pop())
+ dtype = ' '.join(first_arg)
+
+ for param in args:
+ if Re(r'^(\*+)\s*(.*)').match(param):
+ r = Re(r'^(\*+)\s*(.*)')
+ if not r.match(param):
+ self.emit_warning(ln, f"Invalid param: {param}")
+ continue
+
+ param = r.group(1)
+
+ self.save_struct_actual(r.group(2))
+ self.push_parameter(ln, decl_type, r.group(2),
+ f"{dtype} {r.group(1)}",
+ arg, declaration_name)
+
+ elif Re(r'(.*?):(\w+)').search(param):
+ r = Re(r'(.*?):(\w+)')
+ if not r.match(param):
+ self.emit_warning(ln, f"Invalid param: {param}")
+ continue
+
+ if dtype != "": # Skip unnamed bit-fields
+ self.save_struct_actual(r.group(1))
+ self.push_parameter(ln, decl_type, r.group(1),
+ f"{dtype}:{r.group(2)}",
+ arg, declaration_name)
+ else:
+ self.save_struct_actual(param)
+ self.push_parameter(ln, decl_type, param, dtype,
+ arg, declaration_name)
+
+ def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck):
+ """
+ Check for errors inside sections, emitting warnings if not found
+ parameters are described.
+ """
+
+ sects = sectcheck.split()
+ prms = prmscheck.split()
+ err = False
+
+ for sx in range(len(sects)): # pylint: disable=C0200
+ err = True
+ for px in range(len(prms)): # pylint: disable=C0200
+ prm_clean = prms[px]
+ prm_clean = Re(r'\[.*\]').sub('', prm_clean)
+ prm_clean = attribute.sub('', prm_clean)
+
+ # ignore array size in a parameter string;
+ # however, the original param string may contain
+ # spaces, e.g.: addr[6 + 2]
+ # and this appears in @prms as "addr[6" since the
+ # parameter list is split at spaces;
+ # hence just ignore "[..." for the sections check;
+ prm_clean = Re(r'\[.*').sub('', prm_clean)
+
+ if prm_clean == sects[sx]:
+ err = False
+ break
+
+ if err:
+ if decl_type == 'function':
+ dname = f"{decl_type} parameter"
+ else:
+ dname = f"{decl_type} member"
+
+ self.emit_warning(ln,
+ f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
+
+ def check_return_section(self, ln, declaration_name, return_type):
+ """
+ If the function doesn't return void, warns about the lack of a
+ return description.
+ """
+
+ if not self.config.wreturn:
+ return
+
+ # Ignore an empty return type (It's a macro)
+ # Ignore functions with a "void" return type (but not "void *")
+ if not return_type or Re(r'void\s*\w*\s*$').search(return_type):
+ return
+
+ if not self.entry.sections.get("Return", None):
+ self.emit_warning(ln,
+ f"No description found for return value of '{declaration_name}'")
+
+ def dump_struct(self, ln, proto):
+ """
+ Store an entry for an struct or union
+ """
+
+ type_pattern = r'(struct|union)'
+
+ qualifiers = [
+ "__attribute__",
+ "__packed",
+ "__aligned",
+ "____cacheline_aligned_in_smp",
+ "____cacheline_aligned",
+ ]
+
+ definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?"
+ struct_members = Re(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)')
+
+ # Extract struct/union definition
+ members = None
+ declaration_name = None
+ decl_type = None
+
+ r = Re(type_pattern + r'\s+(\w+)\s*' + definition_body)
+ if r.search(proto):
+ decl_type = r.group(1)
+ declaration_name = r.group(2)
+ members = r.group(3)
+ else:
+ r = Re(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;')
+
+ if r.search(proto):
+ decl_type = r.group(1)
+ declaration_name = r.group(3)
+ members = r.group(2)
+
+ if not members:
+ self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
+ self.config.errors += 1
+ return
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln,
+ f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
+ return
+
+ args_pattern = r'([^,)]+)'
+
+ sub_prefixes = [
+ (Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''),
+ (Re(r'\/\*\s*private:.*', re.S | re.I), ''),
+
+ # Strip comments
+ (Re(r'\/\*.*?\*\/', re.S), ''),
+
+ # Strip attributes
+ (attribute, ' '),
+ (Re(r'\s*__aligned\s*\([^;]*\)', re.S), ' '),
+ (Re(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '),
+ (Re(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '),
+ (Re(r'\s*__packed\s*', re.S), ' '),
+ (Re(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '),
+ (Re(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
+ (Re(r'\s*____cacheline_aligned', re.S), ' '),
+
+ # Unwrap struct_group macros based on this definition:
+ # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
+ # which has variants like: struct_group(NAME, MEMBERS...)
+ # Only MEMBERS arguments require documentation.
+ #
+ # Parsing them happens on two steps:
+ #
+ # 1. drop struct group arguments that aren't at MEMBERS,
+ # storing them as STRUCT_GROUP(MEMBERS)
+ #
+ # 2. remove STRUCT_GROUP() ancillary macro.
+ #
+ # The original logic used to remove STRUCT_GROUP() using an
+ # advanced regex:
+ #
+ # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;
+ #
+ # with two patterns that are incompatible with
+ # Python re module, as it has:
+ #
+ # - a recursive pattern: (?1)
+ # - an atomic grouping: (?>...)
+ #
+ # I tried a simpler version: but it didn't work either:
+ # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*;
+ #
+ # As it doesn't properly match the end parenthesis on some cases.
+ #
+ # So, a better solution was crafted: there's now a NestedMatch
+ # class that ensures that delimiters after a search are properly
+ # matched. So, the implementation to drop STRUCT_GROUP() will be
+ # handled in separate.
+
+ (Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
+ (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
+ (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
+ (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
+
+ # Replace macros
+ #
+ # TODO: it is better to also move those to the NestedMatch logic,
+ # to ensure that parenthesis will be properly matched.
+
+ (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
+ (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
+ (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
+ (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
+ (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
+ (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
+ (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'),
+ (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'),
+ (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),
+ ]
+
+ # Regexes here are guaranteed to have the end limiter matching
+ # the start delimiter. Yet, right now, only one replace group
+ # is allowed.
+
+ sub_nested_prefixes = [
+ (re.compile(r'\bSTRUCT_GROUP\('), r'\1'),
+ ]
+
+ for search, sub in sub_prefixes:
+ members = search.sub(sub, members)
+
+ nested = NestedMatch()
+
+ for search, sub in sub_nested_prefixes:
+ members = nested.sub(search, sub, members)
+
+ # Keeps the original declaration as-is
+ declaration = members
+
+ # Split nested struct/union elements
+ #
+ # This loop was simpler at the original kernel-doc perl version, as
+ # while ($members =~ m/$struct_members/) { ... }
+ # reads 'members' string on each interaction.
+ #
+ # Python behavior is different: it parses 'members' only once,
+ # creating a list of tuples from the first interaction.
+ #
+ # On other words, this won't get nested structs.
+ #
+ # So, we need to have an extra loop on Python to override such
+ # re limitation.
+
+ while True:
+ tuples = struct_members.findall(members)
+ if not tuples:
+ break
+
+ for t in tuples:
+ newmember = ""
+ maintype = t[0]
+ s_ids = t[5]
+ content = t[3]
+
+ oldmember = "".join(t)
+
+ for s_id in s_ids.split(','):
+ s_id = s_id.strip()
+
+ newmember += f"{maintype} {s_id}; "
+ s_id = Re(r'[:\[].*').sub('', s_id)
+ s_id = Re(r'^\s*\**(\S+)\s*').sub(r'\1', s_id)
+
+ for arg in content.split(';'):
+ arg = arg.strip()
+
+ if not arg:
+ continue
+
+ r = Re(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)')
+ if r.match(arg):
+ # Pointer-to-function
+ dtype = r.group(1)
+ name = r.group(2)
+ extra = r.group(3)
+
+ if not name:
+ continue
+
+ if not s_id:
+ # Anonymous struct/union
+ newmember += f"{dtype}{name}{extra}; "
+ else:
+ newmember += f"{dtype}{s_id}.{name}{extra}; "
+
+ else:
+ arg = arg.strip()
+ # Handle bitmaps
+ arg = Re(r':\s*\d+\s*').sub('', arg)
+
+ # Handle arrays
+ arg = Re(r'\[.*\]').sub('', arg)
+
+ # Handle multiple IDs
+ arg = Re(r'\s*,\s*').sub(',', arg)
+
+ r = Re(r'(.*)\s+([\S+,]+)')
+
+ if r.search(arg):
+ dtype = r.group(1)
+ names = r.group(2)
+ else:
+ newmember += f"{arg}; "
+ continue
+
+ for name in names.split(','):
+ name = Re(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip()
+
+ if not name:
+ continue
+
+ if not s_id:
+ # Anonymous struct/union
+ newmember += f"{dtype} {name}; "
+ else:
+ newmember += f"{dtype} {s_id}.{name}; "
+
+ members = members.replace(oldmember, newmember)
+
+ # Ignore other nested elements, like enums
+ members = re.sub(r'(\{[^\{\}]*\})', '', members)
+
+ self.create_parameter_list(ln, decl_type, members, ';',
+ declaration_name)
+ self.check_sections(ln, declaration_name, decl_type,
+ self.entry.sectcheck, self.entry.struct_actual)
+
+ # Adjust declaration for better display
+ declaration = Re(r'([\{;])').sub(r'\1\n', declaration)
+ declaration = Re(r'\}\s+;').sub('};', declaration)
+
+ # Better handle inlined enums
+ while True:
+ r = Re(r'(enum\s+\{[^\}]+),([^\n])')
+ if not r.search(declaration):
+ break
+
+ declaration = r.sub(r'\1,\n\2', declaration)
+
+ def_args = declaration.split('\n')
+ level = 1
+ declaration = ""
+ for clause in def_args:
+
+ clause = clause.strip()
+ clause = Re(r'\s+').sub(' ', clause, count=1)
+
+ if not clause:
+ continue
+
+ if '}' in clause and level > 1:
+ level -= 1
+
+ if not Re(r'^\s*#').match(clause):
+ declaration += "\t" * level
+
+ declaration += "\t" + clause + "\n"
+ if "{" in clause and "}" not in clause:
+ level += 1
+
+ self.output_declaration(decl_type, declaration_name,
+ struct=declaration_name,
+ module=self.entry.modulename,
+ definition=declaration,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+
+ def dump_enum(self, ln, proto):
+ """
+ Stores an enum inside self.entries array.
+ """
+
+ # Ignore members marked private
+ proto = Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto)
+ proto = Re(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto)
+
+ # Strip comments
+ proto = Re(r'\/\*.*?\*\/', flags=re.S).sub('', proto)
+
+ # Strip #define macros inside enums
+ proto = Re(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto)
+
+ members = None
+ declaration_name = None
+
+ r = Re(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;')
+ if r.search(proto):
+ declaration_name = r.group(2)
+ members = r.group(1).rstrip()
+ else:
+ r = Re(r'enum\s+(\w*)\s*\{(.*)\}')
+ if r.match(proto):
+ declaration_name = r.group(1)
+ members = r.group(2).rstrip()
+
+ if not members:
+ self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
+ self.config.errors += 1
+ return
+
+ if self.entry.identifier != declaration_name:
+ if self.entry.identifier == "":
+ self.emit_warning(ln,
+ f"{proto}: wrong kernel-doc identifier on prototype")
+ else:
+ self.emit_warning(ln,
+ f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
+ return
+
+ if not declaration_name:
+ declaration_name = "(anonymous)"
+
+ member_set = set()
+
+ members = Re(r'\([^;]*?[\)]').sub('', members)
+
+ for arg in members.split(','):
+ if not arg:
+ continue
+ arg = Re(r'^\s*(\w+).*').sub(r'\1', arg)
+ self.entry.parameterlist.append(arg)
+ if arg not in self.entry.parameterdescs:
+ self.entry.parameterdescs[arg] = self.undescribed
+ if self.show_warnings("enum", declaration_name):
+ self.emit_warning(ln,
+ f"Enum value '{arg}' not described in enum '{declaration_name}'")
+ member_set.add(arg)
+
+ for k in self.entry.parameterdescs:
+ if k not in member_set:
+ if self.show_warnings("enum", declaration_name):
+ self.emit_warning(ln,
+ f"Excess enum value '%{k}' description in '{declaration_name}'")
+
+ self.output_declaration('enum', declaration_name,
+ enum=declaration_name,
+ module=self.config.modulename,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+
+ def dump_declaration(self, ln, prototype):
+ """
+ Stores a data declaration inside self.entries array.
+ """
+
+ if self.entry.decl_type == "enum":
+ self.dump_enum(ln, prototype)
+ return
+
+ if self.entry.decl_type == "typedef":
+ self.dump_typedef(ln, prototype)
+ return
+
+ if self.entry.decl_type in ["union", "struct"]:
+ self.dump_struct(ln, prototype)
+ return
+
+ # TODO: handle other types
+ self.output_declaration(self.entry.decl_type, prototype,
+ entry=self.entry)
+
+ def dump_function(self, ln, prototype):
+ """
+ Stores a function of function macro inside self.entries array.
+ """
+
+ func_macro = False
+ return_type = ''
+ decl_type = 'function'
+
+ # Prefixes that would be removed
+ sub_prefixes = [
+ (r"^static +", "", 0),
+ (r"^extern +", "", 0),
+ (r"^asmlinkage +", "", 0),
+ (r"^inline +", "", 0),
+ (r"^__inline__ +", "", 0),
+ (r"^__inline +", "", 0),
+ (r"^__always_inline +", "", 0),
+ (r"^noinline +", "", 0),
+ (r"^__FORTIFY_INLINE +", "", 0),
+ (r"__init +", "", 0),
+ (r"__init_or_module +", "", 0),
+ (r"__deprecated +", "", 0),
+ (r"__flatten +", "", 0),
+ (r"__meminit +", "", 0),
+ (r"__must_check +", "", 0),
+ (r"__weak +", "", 0),
+ (r"__sched +", "", 0),
+ (r"_noprof", "", 0),
+ (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0),
+ (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0),
+ (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0),
+ (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0),
+ (r"__attribute_const__ +", "", 0),
+
+ # It seems that Python support for re.X is broken:
+ # At least for me (Python 3.13), this didn't work
+# (r"""
+# __attribute__\s*\(\(
+# (?:
+# [\w\s]+ # attribute name
+# (?:\([^)]*\))? # attribute arguments
+# \s*,? # optional comma at the end
+# )+
+# \)\)\s+
+# """, "", re.X),
+
+ # So, remove whitespaces and comments from it
+ (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0),
+ ]
+
+ for search, sub, flags in sub_prefixes:
+ prototype = Re(search, flags).sub(sub, prototype)
+
+ # Macros are a special case, as they change the prototype format
+ new_proto = Re(r"^#\s*define\s+").sub("", prototype)
+ if new_proto != prototype:
+ is_define_proto = True
+ prototype = new_proto
+ else:
+ is_define_proto = False
+
+ # Yes, this truly is vile. We are looking for:
+ # 1. Return type (may be nothing if we're looking at a macro)
+ # 2. Function name
+ # 3. Function parameters.
+ #
+ # All the while we have to watch out for function pointer parameters
+ # (which IIRC is what the two sections are for), C types (these
+ # regexps don't even start to express all the possibilities), and
+ # so on.
+ #
+ # If you mess with these regexps, it's a good idea to check that
+ # the following functions' documentation still comes out right:
+ # - parport_register_device (function pointer parameters)
+ # - atomic_set (macro)
+ # - pci_match_device, __copy_to_user (long return type)
+
+ name = r'[a-zA-Z0-9_~:]+'
+ prototype_end1 = r'[^\(]*'
+ prototype_end2 = r'[^\{]*'
+ prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)'
+
+ # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group.
+ # So, this needs to be mapped in Python with (?:...)? or (?:...)+
+
+ type1 = r'(?:[\w\s]+)?'
+ type2 = r'(?:[\w\s]+\*+)+'
+
+ found = False
+
+ if is_define_proto:
+ r = Re(r'^()(' + name + r')\s+')
+
+ if r.search(prototype):
+ return_type = ''
+ declaration_name = r.group(2)
+ func_macro = True
+
+ found = True
+
+ if not found:
+ patterns = [
+ rf'^()({name})\s*{prototype_end}',
+ rf'^({type1})\s+({name})\s*{prototype_end}',
+ rf'^({type2})\s*({name})\s*{prototype_end}',
+ ]
+
+ for p in patterns:
+ r = Re(p)
+
+ if r.match(prototype):
+
+ return_type = r.group(1)
+ declaration_name = r.group(2)
+ args = r.group(3)
+
+ self.create_parameter_list(ln, decl_type, args, ',',
+ declaration_name)
+
+ found = True
+ break
+ if not found:
+ self.emit_warning(ln,
+ f"cannot understand function prototype: '{prototype}'")
+ return
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln,
+ f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
+ return
+
+ prms = " ".join(self.entry.parameterlist)
+ self.check_sections(ln, declaration_name, "function",
+ self.entry.sectcheck, prms)
+
+ self.check_return_section(ln, declaration_name, return_type)
+
+ if 'typedef' in return_type:
+ self.output_declaration(decl_type, declaration_name,
+ function=declaration_name,
+ typedef=True,
+ module=self.config.modulename,
+ functiontype=return_type,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose,
+ func_macro=func_macro)
+ else:
+ self.output_declaration(decl_type, declaration_name,
+ function=declaration_name,
+ typedef=False,
+ module=self.config.modulename,
+ functiontype=return_type,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose,
+ func_macro=func_macro)
+
+ def dump_typedef(self, ln, proto):
+ """
+ Stores a typedef inside self.entries array.
+ """
+
+ typedef_type = r'((?:\s+[\w\*]+\b){1,8})\s*'
+ typedef_ident = r'\*?\s*(\w\S+)\s*'
+ typedef_args = r'\s*\((.*)\);'
+
+ typedef1 = Re(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args)
+ typedef2 = Re(r'typedef' + typedef_type + typedef_ident + typedef_args)
+
+ # Strip comments
+ proto = Re(r'/\*.*?\*/', flags=re.S).sub('', proto)
+
+ # Parse function typedef prototypes
+ for r in [typedef1, typedef2]:
+ if not r.match(proto):
+ continue
+
+ return_type = r.group(1).strip()
+ declaration_name = r.group(2)
+ args = r.group(3)
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln,
+ f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+ return
+
+ decl_type = 'function'
+ self.create_parameter_list(ln, decl_type, args, ',', declaration_name)
+
+ self.output_declaration(decl_type, declaration_name,
+ function=declaration_name,
+ typedef=True,
+ module=self.entry.modulename,
+ functiontype=return_type,
+ parameterlist=self.entry.parameterlist,
+ parameterdescs=self.entry.parameterdescs,
+ parametertypes=self.entry.parametertypes,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+ return
+
+ # Handle nested parentheses or brackets
+ r = Re(r'(\(*.\)\s*|\[*.\]\s*);$')
+ while r.search(proto):
+ proto = r.sub('', proto)
+
+ # Parse simple typedefs
+ r = Re(r'typedef.*\s+(\w+)\s*;')
+ if r.match(proto):
+ declaration_name = r.group(1)
+
+ if self.entry.identifier != declaration_name:
+ self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+ return
+
+ self.output_declaration('typedef', declaration_name,
+ typedef=declaration_name,
+ module=self.entry.modulename,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections,
+ purpose=self.entry.declaration_purpose)
+ return
+
+ self.emit_warning(ln, "error: Cannot parse typedef!")
+ self.config.errors += 1
+
+ @staticmethod
+ def process_export(function_table, line):
+ """
+ process EXPORT_SYMBOL* tags
+
+ This method is called both internally and externally, so, it
+ doesn't use self.
+ """
+
+ if export_symbol.search(line):
+ symbol = export_symbol.group(2)
+ function_table.add(symbol)
+
+ if export_symbol_ns.search(line):
+ symbol = export_symbol_ns.group(2)
+ function_table.add(symbol)
+
+ def process_normal(self, ln, line):
+ """
+ STATE_NORMAL: looking for the /** to begin everything.
+ """
+
+ if not doc_start.match(line):
+ return
+
+ # start a new entry
+ self.reset_state(ln + 1)
+ self.entry.in_doc_sect = False
+
+ # next line is always the function name
+ self.state = self.STATE_NAME
+
+ def process_name(self, ln, line):
+ """
+ STATE_NAME: Looking for the "name - description" line
+ """
+
+ if doc_block.search(line):
+ self.entry.new_start_line = ln
+
+ if not doc_block.group(1):
+ self.entry.section = self.section_intro
+ else:
+ self.entry.section = doc_block.group(1)
+
+ self.state = self.STATE_DOCBLOCK
+ return
+
+ if doc_decl.search(line):
+ self.entry.identifier = doc_decl.group(1)
+ self.entry.is_kernel_comment = False
+
+ decl_start = str(doc_com) # comment block asterisk
+ fn_type = r"(?:\w+\s*\*\s*)?" # type (for non-functions)
+ parenthesis = r"(?:\(\w*\))?" # optional parenthesis on function
+ decl_end = r"(?:[-:].*)" # end of the name part
+
+ # test for pointer declaration type, foo * bar() - desc
+ r = Re(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$")
+ if r.search(line):
+ self.entry.identifier = r.group(1)
+
+ # Test for data declaration
+ r = Re(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)")
+ if r.search(line):
+ self.entry.decl_type = r.group(1)
+ self.entry.identifier = r.group(2)
+ self.entry.is_kernel_comment = True
+ else:
+ # Look for foo() or static void foo() - description;
+ # or misspelt identifier
+
+ r1 = Re(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$")
+ r2 = Re(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$")
+
+ for r in [r1, r2]:
+ if r.search(line):
+ self.entry.identifier = r.group(1)
+ self.entry.decl_type = "function"
+
+ r = Re(r"define\s+")
+ self.entry.identifier = r.sub("", self.entry.identifier)
+ self.entry.is_kernel_comment = True
+ break
+
+ self.entry.identifier = self.entry.identifier.strip(" ")
+
+ self.state = self.STATE_BODY
+
+ # if there's no @param blocks need to set up default section here
+ self.entry.section = self.section_default
+ self.entry.new_start_line = ln + 1
+
+ r = Re("[-:](.*)")
+ if r.search(line):
+ # strip leading/trailing/multiple spaces
+ self.entry.descr = r.group(1).strip(" ")
+
+ r = Re(r"\s+")
+ self.entry.descr = r.sub(" ", self.entry.descr)
+ self.entry.declaration_purpose = self.entry.descr
+ self.state = self.STATE_BODY_MAYBE
+ else:
+ self.entry.declaration_purpose = ""
+
+ if not self.entry.is_kernel_comment:
+ self.emit_warning(ln,
+ f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
+ self.state = self.STATE_NORMAL
+
+ if not self.entry.declaration_purpose and self.config.wshort_desc:
+ self.emit_warning(ln,
+ f"missing initial short description on line:\n{line}")
+
+ if not self.entry.identifier and self.entry.decl_type != "enum":
+ self.emit_warning(ln,
+ f"wrong kernel-doc identifier on line:\n{line}")
+ self.state = self.STATE_NORMAL
+
+ if self.config.verbose:
+ self.emit_warning(ln,
+ f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
+ warning=False)
+
+ return
+
+ # Failed to find an identifier. Emit a warning
+ self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
+
+ def process_body(self, ln, line):
+ """
+ STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.
+ """
+
+ if self.state == self.STATE_BODY_WITH_BLANK_LINE:
+ r = Re(r"\s*\*\s?\S")
+ if r.match(line):
+ self.dump_section()
+ self.entry.section = self.section_default
+ self.entry.new_start_line = line
+ self.entry.contents = ""
+
+ if doc_sect.search(line):
+ self.entry.in_doc_sect = True
+ newsection = doc_sect.group(1)
+
+ if newsection.lower() in ["description", "context"]:
+ newsection = newsection.title()
+
+ # Special case: @return is a section, not a param description
+ if newsection.lower() in ["@return", "@returns",
+ "return", "returns"]:
+ newsection = "Return"
+
+ # Perl kernel-doc has a check here for contents before sections.
+ # the logic there is always false, as in_doc_sect variable is
+ # always true. So, just don't implement Wcontents_before_sections
+
+ # .title()
+ newcontents = doc_sect.group(2)
+ if not newcontents:
+ newcontents = ""
+
+ if self.entry.contents.strip("\n"):
+ self.dump_section()
+
+ self.entry.new_start_line = ln
+ self.entry.section = newsection
+ self.entry.leading_space = None
+
+ self.entry.contents = newcontents.lstrip()
+ if self.entry.contents:
+ self.entry.contents += "\n"
+
+ self.state = self.STATE_BODY
+ return
+
+ if doc_end.search(line):
+ self.dump_section()
+
+ # Look for doc_com + <text> + doc_end:
+ r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
+ if r.match(line):
+ self.emit_warning(ln, f"suspicious ending line: {line}")
+
+ self.entry.prototype = ""
+ self.entry.new_start_line = ln + 1
+
+ self.state = self.STATE_PROTO
+ return
+
+ if doc_content.search(line):
+ cont = doc_content.group(1)
+
+ if cont == "":
+ if self.entry.section == self.section_context:
+ self.dump_section()
+
+ self.entry.new_start_line = ln
+ self.state = self.STATE_BODY
+ else:
+ if self.entry.section != self.section_default:
+ self.state = self.STATE_BODY_WITH_BLANK_LINE
+ else:
+ self.state = self.STATE_BODY
+
+ self.entry.contents += "\n"
+
+ elif self.state == self.STATE_BODY_MAYBE:
+
+ # Continued declaration purpose
+ self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip()
+ self.entry.declaration_purpose += " " + cont
+
+ r = Re(r"\s+")
+ self.entry.declaration_purpose = r.sub(' ',
+ self.entry.declaration_purpose)
+
+ else:
+ if self.entry.section.startswith('@') or \
+ self.entry.section == self.section_context:
+ if self.entry.leading_space is None:
+ r = Re(r'^(\s+)')
+ if r.match(cont):
+ self.entry.leading_space = len(r.group(1))
+ else:
+ self.entry.leading_space = 0
+
+ # Double-check if leading space are realy spaces
+ pos = 0
+ for i in range(0, self.entry.leading_space):
+ if cont[i] != " ":
+ break
+ pos += 1
+
+ cont = cont[pos:]
+
+ # NEW LOGIC:
+ # In case it is different, update it
+ if self.entry.leading_space != pos:
+ self.entry.leading_space = pos
+
+ self.entry.contents += cont + "\n"
+ return
+
+ # Unknown line, ignore
+ self.emit_warning(ln, f"bad line: {line}")
+
+ def process_inline(self, ln, line):
+ """STATE_INLINE: docbook comments within a prototype."""
+
+ if self.inline_doc_state == self.STATE_INLINE_NAME and \
+ doc_inline_sect.search(line):
+ self.entry.section = doc_inline_sect.group(1)
+ self.entry.new_start_line = ln
+
+ self.entry.contents = doc_inline_sect.group(2).lstrip()
+ if self.entry.contents != "":
+ self.entry.contents += "\n"
+
+ self.inline_doc_state = self.STATE_INLINE_TEXT
+ # Documentation block end */
+ return
+
+ if doc_inline_end.search(line):
+ if self.entry.contents not in ["", "\n"]:
+ self.dump_section()
+
+ self.state = self.STATE_PROTO
+ self.inline_doc_state = self.STATE_INLINE_NA
+ return
+
+ if doc_content.search(line):
+ if self.inline_doc_state == self.STATE_INLINE_TEXT:
+ self.entry.contents += doc_content.group(1) + "\n"
+ if not self.entry.contents.strip(" ").rstrip("\n"):
+ self.entry.contents = ""
+
+ elif self.inline_doc_state == self.STATE_INLINE_NAME:
+ self.emit_warning(ln,
+ f"Incorrect use of kernel-doc format: {line}")
+
+ self.inline_doc_state = self.STATE_INLINE_ERROR
+
+ def syscall_munge(self, ln, proto): # pylint: disable=W0613
+ """
+ Handle syscall definitions
+ """
+
+ is_void = False
+
+ # Strip newlines/CR's
+ proto = re.sub(r'[\r\n]+', ' ', proto)
+
+ # Check if it's a SYSCALL_DEFINE0
+ if 'SYSCALL_DEFINE0' in proto:
+ is_void = True
+
+ # Replace SYSCALL_DEFINE with correct return type & function name
+ proto = Re(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
+
+ r = Re(r'long\s+(sys_.*?),')
+ if r.search(proto):
+ proto = proto.replace(',', '(', count=1)
+ elif is_void:
+ proto = proto.replace(')', '(void)', count=1)
+
+ # Now delete all of the odd-numbered commas in the proto
+ # so that argument types & names don't have a comma between them
+ count = 0
+ length = len(proto)
+
+ if is_void:
+ length = 0 # skip the loop if is_void
+
+ for ix in range(length):
+ if proto[ix] == ',':
+ count += 1
+ if count % 2 == 1:
+ proto = proto[:ix] + ' ' + proto[ix + 1:]
+
+ return proto
+
+ def tracepoint_munge(self, ln, proto):
+ """
+ Handle tracepoint definitions
+ """
+
+ tracepointname = None
+ tracepointargs = None
+
+ # Match tracepoint name based on different patterns
+ r = Re(r'TRACE_EVENT\((.*?),')
+ if r.search(proto):
+ tracepointname = r.group(1)
+
+ r = Re(r'DEFINE_SINGLE_EVENT\((.*?),')
+ if r.search(proto):
+ tracepointname = r.group(1)
+
+ r = Re(r'DEFINE_EVENT\((.*?),(.*?),')
+ if r.search(proto):
+ tracepointname = r.group(2)
+
+ if tracepointname:
+ tracepointname = tracepointname.lstrip()
+
+ r = Re(r'TP_PROTO\((.*?)\)')
+ if r.search(proto):
+ tracepointargs = r.group(1)
+
+ if not tracepointname or not tracepointargs:
+ self.emit_warning(ln,
+ f"Unrecognized tracepoint format:\n{proto}\n")
+ else:
+ proto = f"static inline void trace_{tracepointname}({tracepointargs})"
+ self.entry.identifier = f"trace_{self.entry.identifier}"
+
+ return proto
+
+ def process_proto_function(self, ln, line):
+ """Ancillary routine to process a function prototype"""
+
+ # strip C99-style comments to end of line
+ r = Re(r"\/\/.*$", re.S)
+ line = r.sub('', line)
+
+ if Re(r'\s*#\s*define').match(line):
+ self.entry.prototype = line
+ elif line.startswith('#'):
+ # Strip other macros like #ifdef/#ifndef/#endif/...
+ pass
+ else:
+ r = Re(r'([^\{]*)')
+ if r.match(line):
+ self.entry.prototype += r.group(1) + " "
+
+ if '{' in line or ';' in line or Re(r'\s*#\s*define').match(line):
+ # strip comments
+ r = Re(r'/\*.*?\*/')
+ self.entry.prototype = r.sub('', self.entry.prototype)
+
+ # strip newlines/cr's
+ r = Re(r'[\r\n]+')
+ self.entry.prototype = r.sub(' ', self.entry.prototype)
+
+ # strip leading spaces
+ r = Re(r'^\s+')
+ self.entry.prototype = r.sub('', self.entry.prototype)
+
+ # Handle self.entry.prototypes for function pointers like:
+ # int (*pcs_config)(struct foo)
+
+ r = Re(r'^(\S+\s+)\(\s*\*(\S+)\)')
+ self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
+
+ if 'SYSCALL_DEFINE' in self.entry.prototype:
+ self.entry.prototype = self.syscall_munge(ln,
+ self.entry.prototype)
+
+ r = Re(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
+ if r.search(self.entry.prototype):
+ self.entry.prototype = self.tracepoint_munge(ln,
+ self.entry.prototype)
+
+ self.dump_function(ln, self.entry.prototype)
+ self.reset_state(ln)
+
+ def process_proto_type(self, ln, line):
+ """Ancillary routine to process a type"""
+
+ # Strip newlines/cr's.
+ line = Re(r'[\r\n]+', re.S).sub(' ', line)
+
+ # Strip leading spaces
+ line = Re(r'^\s+', re.S).sub('', line)
+
+ # Strip trailing spaces
+ line = Re(r'\s+$', re.S).sub('', line)
+
+ # Strip C99-style comments to the end of the line
+ line = Re(r"\/\/.*$", re.S).sub('', line)
+
+ # To distinguish preprocessor directive from regular declaration later.
+ if line.startswith('#'):
+ line += ";"
+
+ r = Re(r'([^\{\};]*)([\{\};])(.*)')
+ while True:
+ if r.search(line):
+ if self.entry.prototype:
+ self.entry.prototype += " "
+ self.entry.prototype += r.group(1) + r.group(2)
+
+ self.entry.brcount += r.group(2).count('{')
+ self.entry.brcount -= r.group(2).count('}')
+
+ self.entry.brcount = max(self.entry.brcount, 0)
+
+ if r.group(2) == ';' and self.entry.brcount == 0:
+ self.dump_declaration(ln, self.entry.prototype)
+ self.reset_state(ln)
+ break
+
+ line = r.group(3)
+ else:
+ self.entry.prototype += line
+ break
+
+ def process_proto(self, ln, line):
+ """STATE_PROTO: reading a function/whatever prototype."""
+
+ if doc_inline_oneline.search(line):
+ self.entry.section = doc_inline_oneline.group(1)
+ self.entry.contents = doc_inline_oneline.group(2)
+
+ if self.entry.contents != "":
+ self.entry.contents += "\n"
+ self.dump_section(start_new=False)
+
+ elif doc_inline_start.search(line):
+ self.state = self.STATE_INLINE
+ self.inline_doc_state = self.STATE_INLINE_NAME
+
+ elif self.entry.decl_type == 'function':
+ self.process_proto_function(ln, line)
+
+ else:
+ self.process_proto_type(ln, line)
+
+ def process_docblock(self, ln, line):
+ """STATE_DOCBLOCK: within a DOC: block."""
+
+ if doc_end.search(line):
+ self.dump_section()
+ self.output_declaration("doc", None,
+ sectionlist=self.entry.sectionlist,
+ sections=self.entry.sections, module=self.config.modulename)
+ self.reset_state(ln)
+
+ elif doc_content.search(line):
+ self.entry.contents += doc_content.group(1) + "\n"
+
+ def run(self):
+ """
+ Open and process each line of a C source file.
+ he parsing is controlled via a state machine, and the line is passed
+ to a different process function depending on the state. The process
+ function may update the state as needed.
+ """
+
+ cont = False
+ prev = ""
+ prev_ln = None
+
+ try:
+ with open(self.fname, "r", encoding="utf8",
+ errors="backslashreplace") as fp:
+ for ln, line in enumerate(fp):
+
+ line = line.expandtabs().strip("\n")
+
+ # Group continuation lines on prototypes
+ if self.state == self.STATE_PROTO:
+ if line.endswith("\\"):
+ prev += line.removesuffix("\\")
+ cont = True
+
+ if not prev_ln:
+ prev_ln = ln
+
+ continue
+
+ if cont:
+ ln = prev_ln
+ line = prev + line
+ prev = ""
+ cont = False
+ prev_ln = None
+
+ self.config.log.debug("%d %s%s: %s",
+ ln, self.st_name[self.state],
+ self.st_inline_name[self.inline_doc_state],
+ line)
+
+ # TODO: not all states allow EXPORT_SYMBOL*, so this
+ # can be optimized later on to speedup parsing
+ self.process_export(self.config.function_table, line)
+
+ # Hand this line to the appropriate state handler
+ if self.state == self.STATE_NORMAL:
+ self.process_normal(ln, line)
+ elif self.state == self.STATE_NAME:
+ self.process_name(ln, line)
+ elif self.state in [self.STATE_BODY, self.STATE_BODY_MAYBE,
+ self.STATE_BODY_WITH_BLANK_LINE]:
+ self.process_body(ln, line)
+ elif self.state == self.STATE_INLINE: # scanning for inline parameters
+ self.process_inline(ln, line)
+ elif self.state == self.STATE_PROTO:
+ self.process_proto(ln, line)
+ elif self.state == self.STATE_DOCBLOCK:
+ self.process_docblock(ln, line)
+ except OSError:
+ self.config.log.error(f"Error: Cannot open file {self.fname}")
+ self.config.errors += 1
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 15/39] scripts/kernel-doc.py: move KernelFiles class to a separate file
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (13 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class " Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 16/39] scripts/kernel-doc.py: move output classes " Mauro Carvalho Chehab
` (24 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
The KernelFiles class is the main dispatcher which parses each
source file.
In preparation for letting kerneldoc Sphinx extension to import
Python libraries, move regex ancillary classes to a separate
file.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 220 +--------------------------
scripts/lib/kdoc/kdoc_files.py | 269 +++++++++++++++++++++++++++++++++
2 files changed, 270 insertions(+), 219 deletions(-)
create mode 100755 scripts/lib/kdoc/kdoc_files.py
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 193a30fcfb7c..cd79b2c1b746 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -44,6 +44,7 @@ sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
from kdoc_parser import KernelDoc, type_param
from kdoc_re import Re
+from kdoc_files import KernelFiles
function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
@@ -68,225 +69,6 @@ type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
type_fallback = Re(r"\&([_\w]+)", cache=False)
type_member_func = type_member + Re(r"\(\)", cache=False)
-class GlobSourceFiles:
- """
- Parse C source code file names and directories via an Interactor.
-
- """
-
- def __init__(self, srctree=None, valid_extensions=None):
- """
- Initialize valid extensions with a tuple.
-
- If not defined, assume default C extensions (.c and .h)
-
- It would be possible to use python's glob function, but it is
- very slow, and it is not interactive. So, it would wait to read all
- directories before actually do something.
-
- So, let's use our own implementation.
- """
-
- if not valid_extensions:
- self.extensions = (".c", ".h")
- else:
- self.extensions = valid_extensions
-
- self.srctree = srctree
-
- def _parse_dir(self, dirname):
- """Internal function to parse files recursively"""
-
- with os.scandir(dirname) as obj:
- for entry in obj:
- name = os.path.join(dirname, entry.name)
-
- if entry.is_dir():
- yield from self._parse_dir(name)
-
- if not entry.is_file():
- continue
-
- basename = os.path.basename(name)
-
- if not basename.endswith(self.extensions):
- continue
-
- yield name
-
- def parse_files(self, file_list, file_not_found_cb):
- for fname in file_list:
- if self.srctree:
- f = os.path.join(self.srctree, fname)
- else:
- f = fname
-
- if os.path.isdir(f):
- yield from self._parse_dir(f)
- elif os.path.isfile(f):
- yield f
- elif file_not_found_cb:
- file_not_found_cb(fname)
-
-
-class KernelFiles():
-
- def parse_file(self, fname):
-
- doc = KernelDoc(self.config, fname)
- doc.run()
-
- return doc
-
- def process_export_file(self, fname):
- try:
- with open(fname, "r", encoding="utf8",
- errors="backslashreplace") as fp:
- for line in fp:
- KernelDoc.process_export(self.config.function_table, line)
-
- except IOError:
- print(f"Error: Cannot open fname {fname}", fname=sys.stderr)
- self.config.errors += 1
-
- def file_not_found_cb(self, fname):
- self.config.log.error("Cannot find file %s", fname)
- self.config.errors += 1
-
- def __init__(self, files=None, verbose=False, out_style=None,
- werror=False, wreturn=False, wshort_desc=False,
- wcontents_before_sections=False,
- logger=None, modulename=None, export_file=None):
- """Initialize startup variables and parse all files"""
-
-
- if not verbose:
- verbose = bool(os.environ.get("KBUILD_VERBOSE", 0))
-
- if not modulename:
- modulename = "Kernel API"
-
- dt = datetime.now()
- if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
- # use UTC TZ
- to_zone = tz.gettz('UTC')
- dt = dt.astimezone(to_zone)
-
- if not werror:
- kcflags = os.environ.get("KCFLAGS", None)
- if kcflags:
- match = re.search(r"(\s|^)-Werror(\s|$)/", kcflags)
- if match:
- werror = True
-
- # reading this variable is for backwards compat just in case
- # someone was calling it with the variable from outside the
- # kernel's build system
- kdoc_werror = os.environ.get("KDOC_WERROR", None)
- if kdoc_werror:
- werror = kdoc_werror
-
- # Set global config data used on all files
- self.config = argparse.Namespace
-
- self.config.verbose = verbose
- self.config.werror = werror
- self.config.wreturn = wreturn
- self.config.wshort_desc = wshort_desc
- self.config.wcontents_before_sections = wcontents_before_sections
- self.config.modulename = modulename
-
- self.config.function_table = set()
- self.config.source_map = {}
-
- if not logger:
- self.config.log = logging.getLogger("kernel-doc")
- else:
- self.config.log = logger
-
- self.config.kernel_version = os.environ.get("KERNELVERSION",
- "unknown kernel version'")
- self.config.src_tree = os.environ.get("SRCTREE", None)
-
- self.out_style = out_style
- self.export_file = export_file
-
- # Initialize internal variables
-
- self.config.errors = 0
- self.results = []
-
- self.file_list = files
- self.files = set()
-
- def parse(self):
- """
- Parse all files
- """
-
- glob = GlobSourceFiles(srctree=self.config.src_tree)
-
- # Let's use a set here to avoid duplicating files
-
- for fname in glob.parse_files(self.file_list, self.file_not_found_cb):
- if fname in self.files:
- continue
-
- self.files.add(fname)
-
- res = self.parse_file(fname)
- self.results.append((res.fname, res.entries))
-
- if not self.files:
- sys.exit(1)
-
- # If a list of export files was provided, parse EXPORT_SYMBOL*
- # from the ones not already parsed
-
- if self.export_file:
- files = self.files
-
- glob = GlobSourceFiles(srctree=self.config.src_tree)
-
- for fname in glob.parse_files(self.export_file,
- self.file_not_found_cb):
- if fname not in files:
- files.add(fname)
-
- self.process_export_file(fname)
-
- def out_msg(self, fname, name, arg):
- # TODO: filter out unwanted parts
-
- return self.out_style.msg(fname, name, arg)
-
- def msg(self, enable_lineno=False, export=False, internal=False,
- symbol=None, nosymbol=None):
-
- function_table = self.config.function_table
-
- if symbol:
- for s in symbol:
- function_table.add(s)
-
- # Output none mode: only warnings will be shown
- if not self.out_style:
- return
-
- self.out_style.set_config(self.config)
-
- self.out_style.set_filter(export, internal, symbol, nosymbol,
- function_table, enable_lineno)
-
- for fname, arg_tuple in self.results:
- for name, arg in arg_tuple:
- if self.out_msg(fname, name, arg):
- ln = arg.get("ln", 0)
- dtype = arg.get('type', "")
-
- self.config.log.warning("%s:%d Can't handle %s",
- fname, ln, dtype)
-
class OutputFormat:
# output mode.
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
new file mode 100755
index 000000000000..76dd53611c08
--- /dev/null
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python3
+# pylint: disable=R0903,R0913,R0914,R0917
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+# TODO: implement warning filtering
+
+"""
+Parse lernel-doc tags on multiple kernel source files.
+"""
+
+import argparse
+import logging
+import os
+import re
+import sys
+from datetime import datetime
+
+from dateutil import tz
+
+from kdoc_parser import KernelDoc
+
+
+class GlobSourceFiles:
+ """
+ Parse C source code file names and directories via an Interactor.
+ """
+
+ def __init__(self, srctree=None, valid_extensions=None):
+ """
+ Initialize valid extensions with a tuple.
+
+ If not defined, assume default C extensions (.c and .h)
+
+ It would be possible to use python's glob function, but it is
+ very slow, and it is not interactive. So, it would wait to read all
+ directories before actually do something.
+
+ So, let's use our own implementation.
+ """
+
+ if not valid_extensions:
+ self.extensions = (".c", ".h")
+ else:
+ self.extensions = valid_extensions
+
+ self.srctree = srctree
+
+ def _parse_dir(self, dirname):
+ """Internal function to parse files recursively"""
+
+ with os.scandir(dirname) as obj:
+ for entry in obj:
+ name = os.path.join(dirname, entry.name)
+
+ if entry.is_dir():
+ yield from self._parse_dir(name)
+
+ if not entry.is_file():
+ continue
+
+ basename = os.path.basename(name)
+
+ if not basename.endswith(self.extensions):
+ continue
+
+ yield name
+
+ def parse_files(self, file_list, file_not_found_cb):
+ """
+ Define an interator to parse all source files from file_list,
+ handling directories if any
+ """
+
+ for fname in file_list:
+ if self.srctree:
+ f = os.path.join(self.srctree, fname)
+ else:
+ f = fname
+
+ if os.path.isdir(f):
+ yield from self._parse_dir(f)
+ elif os.path.isfile(f):
+ yield f
+ elif file_not_found_cb:
+ file_not_found_cb(fname)
+
+
+class KernelFiles():
+ """
+ Parse lernel-doc tags on multiple kernel source files.
+ """
+
+ def parse_file(self, fname):
+ """
+ Parse a single Kernel source.
+ """
+
+ doc = KernelDoc(self.config, fname)
+ doc.run()
+
+ return doc
+
+ def process_export_file(self, fname):
+ """
+ Parses EXPORT_SYMBOL* macros from a single Kernel source file.
+ """
+ try:
+ with open(fname, "r", encoding="utf8",
+ errors="backslashreplace") as fp:
+ for line in fp:
+ KernelDoc.process_export(self.config.function_table, line)
+
+ except IOError:
+ print(f"Error: Cannot open fname {fname}", fname=sys.stderr)
+ self.config.errors += 1
+
+ def file_not_found_cb(self, fname):
+ """
+ Callback to warn if a file was not found.
+ """
+
+ self.config.log.error("Cannot find file %s", fname)
+ self.config.errors += 1
+
+ def __init__(self, files=None, verbose=False, out_style=None,
+ werror=False, wreturn=False, wshort_desc=False,
+ wcontents_before_sections=False,
+ logger=None, modulename=None, export_file=None):
+ """
+ Initialize startup variables and parse all files
+ """
+
+ if not verbose:
+ verbose = bool(os.environ.get("KBUILD_VERBOSE", 0))
+
+ if not modulename:
+ modulename = "Kernel API"
+
+ dt = datetime.now()
+ if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
+ # use UTC TZ
+ to_zone = tz.gettz('UTC')
+ dt = dt.astimezone(to_zone)
+
+ if not werror:
+ kcflags = os.environ.get("KCFLAGS", None)
+ if kcflags:
+ match = re.search(r"(\s|^)-Werror(\s|$)/", kcflags)
+ if match:
+ werror = True
+
+ # reading this variable is for backwards compat just in case
+ # someone was calling it with the variable from outside the
+ # kernel's build system
+ kdoc_werror = os.environ.get("KDOC_WERROR", None)
+ if kdoc_werror:
+ werror = kdoc_werror
+
+ # Set global config data used on all files
+ self.config = argparse.Namespace
+
+ self.config.verbose = verbose
+ self.config.werror = werror
+ self.config.wreturn = wreturn
+ self.config.wshort_desc = wshort_desc
+ self.config.wcontents_before_sections = wcontents_before_sections
+ self.config.modulename = modulename
+
+ self.config.function_table = set()
+ self.config.source_map = {}
+
+ if not logger:
+ self.config.log = logging.getLogger("kernel-doc")
+ else:
+ self.config.log = logger
+
+ self.config.kernel_version = os.environ.get("KERNELVERSION",
+ "unknown kernel version'")
+ self.config.src_tree = os.environ.get("SRCTREE", None)
+
+ self.out_style = out_style
+ self.export_file = export_file
+
+ # Initialize internal variables
+
+ self.config.errors = 0
+ self.results = []
+
+ self.file_list = files
+ self.files = set()
+
+ def parse(self):
+ """
+ Parse all files
+ """
+
+ glob = GlobSourceFiles(srctree=self.config.src_tree)
+
+ # Let's use a set here to avoid duplicating files
+
+ for fname in glob.parse_files(self.file_list, self.file_not_found_cb):
+ if fname in self.files:
+ continue
+
+ self.files.add(fname)
+
+ res = self.parse_file(fname)
+ self.results.append((res.fname, res.entries))
+
+ if not self.files:
+ sys.exit(1)
+
+ # If a list of export files was provided, parse EXPORT_SYMBOL*
+ # from the ones not already parsed
+
+ if self.export_file:
+ files = self.files
+
+ glob = GlobSourceFiles(srctree=self.config.src_tree)
+
+ for fname in glob.parse_files(self.export_file,
+ self.file_not_found_cb):
+ if fname not in files:
+ files.add(fname)
+
+ self.process_export_file(fname)
+
+ def out_msg(self, fname, name, arg):
+ """
+ Output messages from a file name using the output style filtering.
+
+ If output type was not handled by the syler, return False.
+ """
+
+ # NOTE: we can add rules here to filter out unwanted parts,
+ # although OutputFormat.msg already does that.
+
+ return self.out_style.msg(fname, name, arg)
+
+ def msg(self, enable_lineno=False, export=False, internal=False,
+ symbol=None, nosymbol=None):
+ """
+ Interacts over the kernel-doc results and output messages.
+ """
+
+ function_table = self.config.function_table
+
+ if symbol:
+ for s in symbol:
+ function_table.add(s)
+
+ # Output none mode: only warnings will be shown
+ if not self.out_style:
+ return
+
+ self.out_style.set_config(self.config)
+
+ self.out_style.set_filter(export, internal, symbol, nosymbol,
+ function_table, enable_lineno)
+
+ for fname, arg_tuple in self.results:
+ for name, arg in arg_tuple:
+ if self.out_msg(fname, name, arg):
+ ln = arg.get("ln", 0)
+ dtype = arg.get('type', "")
+
+ self.config.log.warning("%s:%d Can't handle %s",
+ fname, ln, dtype)
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 16/39] scripts/kernel-doc.py: move output classes to a separate file
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (14 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 15/39] scripts/kernel-doc.py: move KernelFiles " Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 17/39] scripts/kernel-doc.py: convert message output to an interactor Mauro Carvalho Chehab
` (23 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
In preparation for letting kerneldoc Sphinx extension to import
Python libraries, move kernel-doc output logic to a separate file.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 727 +------------------------------
scripts/lib/kdoc/kdoc_output.py | 735 ++++++++++++++++++++++++++++++++
2 files changed, 738 insertions(+), 724 deletions(-)
create mode 100755 scripts/lib/kdoc/kdoc_output.py
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index cd79b2c1b746..0596c711d448 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -1,7 +1,5 @@
#!/usr/bin/env python3
-# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
-# pylint: disable=C0302,C0103,C0301
-# pylint: disable=C0116,C0115,W0511,W0613
+# pylint: disable=C0103,
# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
# SPDX-License-Identifier: GPL-2.0
@@ -27,14 +25,8 @@ documentation comment syntax.
import argparse
import logging
import os
-import re
import sys
-from datetime import datetime
-from pprint import pformat
-
-from dateutil import tz
-
# Import Python modules
LIB_DIR = "lib/kdoc"
@@ -42,721 +34,8 @@ SRC_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
-from kdoc_parser import KernelDoc, type_param
-from kdoc_re import Re
-from kdoc_files import KernelFiles
-
-function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
-
-# match expressions used to find embedded type information
-type_constant = Re(r"\b``([^\`]+)``\b", cache=False)
-type_constant2 = Re(r"\%([-_*\w]+)", cache=False)
-type_func = Re(r"(\w+)\(\)", cache=False)
-type_param_ref = Re(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
-
-# Special RST handling for func ptr params
-type_fp_param = Re(r"\@(\w+)\(\)", cache=False)
-
-# Special RST handling for structs with func ptr params
-type_fp_param2 = Re(r"\@(\w+->\S+)\(\)", cache=False)
-
-type_env = Re(r"(\$\w+)", cache=False)
-type_enum = Re(r"\&(enum\s*([_\w]+))", cache=False)
-type_struct = Re(r"\&(struct\s*([_\w]+))", cache=False)
-type_typedef = Re(r"\&(typedef\s*([_\w]+))", cache=False)
-type_union = Re(r"\&(union\s*([_\w]+))", cache=False)
-type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
-type_fallback = Re(r"\&([_\w]+)", cache=False)
-type_member_func = type_member + Re(r"\(\)", cache=False)
-
-
-class OutputFormat:
- # output mode.
- OUTPUT_ALL = 0 # output all symbols and doc sections
- OUTPUT_INCLUDE = 1 # output only specified symbols
- OUTPUT_EXPORTED = 2 # output exported symbols
- OUTPUT_INTERNAL = 3 # output non-exported symbols
-
- # Virtual member to be overriden at the inherited classes
- highlights = []
-
- def __init__(self):
- """Declare internal vars and set mode to OUTPUT_ALL"""
-
- self.out_mode = self.OUTPUT_ALL
- self.enable_lineno = None
- self.nosymbol = {}
- self.symbol = None
- self.function_table = set()
- self.config = None
-
- def set_config(self, config):
- self.config = config
-
- def set_filter(self, export, internal, symbol, nosymbol, function_table,
- enable_lineno):
- """
- Initialize filter variables according with the requested mode.
-
- Only one choice is valid between export, internal and symbol.
-
- The nosymbol filter can be used on all modes.
- """
-
- self.enable_lineno = enable_lineno
-
- if symbol:
- self.out_mode = self.OUTPUT_INCLUDE
- function_table = symbol
- elif export:
- self.out_mode = self.OUTPUT_EXPORTED
- elif internal:
- self.out_mode = self.OUTPUT_INTERNAL
- else:
- self.out_mode = self.OUTPUT_ALL
-
- if nosymbol:
- self.nosymbol = set(nosymbol)
-
- if function_table:
- self.function_table = function_table
-
- def highlight_block(self, block):
- """
- Apply the RST highlights to a sub-block of text.
- """
-
- for r, sub in self.highlights:
- block = r.sub(sub, block)
-
- return block
-
- def check_doc(self, name):
- """Check if DOC should be output"""
-
- if self.out_mode == self.OUTPUT_ALL:
- return True
-
- if self.out_mode == self.OUTPUT_INCLUDE:
- if name in self.nosymbol:
- return False
-
- if name in self.function_table:
- return True
-
- return False
-
- def check_declaration(self, dtype, name):
- if name in self.nosymbol:
- return False
-
- if self.out_mode == self.OUTPUT_ALL:
- return True
-
- if self.out_mode in [ self.OUTPUT_INCLUDE, self.OUTPUT_EXPORTED ]:
- if name in self.function_table:
- return True
-
- if self.out_mode == self.OUTPUT_INTERNAL:
- if dtype != "function":
- return True
-
- if name not in self.function_table:
- return True
-
- return False
-
- def check_function(self, fname, name, args):
- return True
-
- def check_enum(self, fname, name, args):
- return True
-
- def check_typedef(self, fname, name, args):
- return True
-
- def msg(self, fname, name, args):
-
- dtype = args.get('type', "")
-
- if dtype == "doc":
- self.out_doc(fname, name, args)
- return False
-
- if not self.check_declaration(dtype, name):
- return False
-
- if dtype == "function":
- self.out_function(fname, name, args)
- return False
-
- if dtype == "enum":
- self.out_enum(fname, name, args)
- return False
-
- if dtype == "typedef":
- self.out_typedef(fname, name, args)
- return False
-
- if dtype in ["struct", "union"]:
- self.out_struct(fname, name, args)
- return False
-
- # Warn if some type requires an output logic
- self.config.log.warning("doesn't now how to output '%s' block",
- dtype)
-
- return True
-
- # Virtual methods to be overridden by inherited classes
- def out_doc(self, fname, name, args):
- pass
-
- def out_function(self, fname, name, args):
- pass
-
- def out_enum(self, fname, name, args):
- pass
-
- def out_typedef(self, fname, name, args):
- pass
-
- def out_struct(self, fname, name, args):
- pass
-
-
-class RestFormat(OutputFormat):
- # """Consts and functions used by ReST output"""
-
- highlights = [
- (type_constant, r"``\1``"),
- (type_constant2, r"``\1``"),
-
- # Note: need to escape () to avoid func matching later
- (type_member_func, r":c:type:`\1\2\3\\(\\) <\1>`"),
- (type_member, r":c:type:`\1\2\3 <\1>`"),
- (type_fp_param, r"**\1\\(\\)**"),
- (type_fp_param2, r"**\1\\(\\)**"),
- (type_func, r"\1()"),
- (type_enum, r":c:type:`\1 <\2>`"),
- (type_struct, r":c:type:`\1 <\2>`"),
- (type_typedef, r":c:type:`\1 <\2>`"),
- (type_union, r":c:type:`\1 <\2>`"),
-
- # in rst this can refer to any type
- (type_fallback, r":c:type:`\1`"),
- (type_param_ref, r"**\1\2**")
- ]
- blankline = "\n"
-
- sphinx_literal = Re(r'^[^.].*::$', cache=False)
- sphinx_cblock = Re(r'^\.\.\ +code-block::', cache=False)
-
- def __init__(self):
- """
- Creates class variables.
-
- Not really mandatory, but it is a good coding style and makes
- pylint happy.
- """
-
- super().__init__()
- self.lineprefix = ""
-
- def print_lineno (self, ln):
- """Outputs a line number"""
-
- if self.enable_lineno and ln:
- print(f".. LINENO {ln}")
-
- def output_highlight(self, args):
- input_text = args
- output = ""
- in_literal = False
- litprefix = ""
- block = ""
-
- for line in input_text.strip("\n").split("\n"):
-
- # If we're in a literal block, see if we should drop out of it.
- # Otherwise, pass the line straight through unmunged.
- if in_literal:
- if line.strip(): # If the line is not blank
- # If this is the first non-blank line in a literal block,
- # figure out the proper indent.
- if not litprefix:
- r = Re(r'^(\s*)')
- if r.match(line):
- litprefix = '^' + r.group(1)
- else:
- litprefix = ""
-
- output += line + "\n"
- elif not Re(litprefix).match(line):
- in_literal = False
- else:
- output += line + "\n"
- else:
- output += line + "\n"
-
- # Not in a literal block (or just dropped out)
- if not in_literal:
- block += line + "\n"
- if self.sphinx_literal.match(line) or self.sphinx_cblock.match(line):
- in_literal = True
- litprefix = ""
- output += self.highlight_block(block)
- block = ""
-
- # Handle any remaining block
- if block:
- output += self.highlight_block(block)
-
- # Print the output with the line prefix
- for line in output.strip("\n").split("\n"):
- print(self.lineprefix + line)
-
- def out_section(self, args, out_reference=False):
- """
- Outputs a block section.
-
- This could use some work; it's used to output the DOC: sections, and
- starts by putting out the name of the doc section itself, but that
- tends to duplicate a header already in the template file.
- """
-
- sectionlist = args.get('sectionlist', [])
- sections = args.get('sections', {})
- section_start_lines = args.get('section_start_lines', {})
-
- for section in sectionlist:
- # Skip sections that are in the nosymbol_table
- if section in self.nosymbol:
- continue
-
- if not self.out_mode == self.OUTPUT_INCLUDE:
- if out_reference:
- print(f".. _{section}:\n")
-
- if not self.symbol:
- print(f'{self.lineprefix}**{section}**\n')
-
- self.print_lineno(section_start_lines.get(section, 0))
- self.output_highlight(sections[section])
- print()
- print()
-
- def out_doc(self, fname, name, args):
- if not self.check_doc(name):
- return
-
- self.out_section(args, out_reference=True)
-
- def out_function(self, fname, name, args):
-
- oldprefix = self.lineprefix
- signature = ""
-
- func_macro = args.get('func_macro', False)
- if func_macro:
- signature = args['function']
- else:
- if args.get('functiontype'):
- signature = args['functiontype'] + " "
- signature += args['function'] + " ("
-
- parameterlist = args.get('parameterlist', [])
- parameterdescs = args.get('parameterdescs', {})
- parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
-
- ln = args.get('ln', 0)
-
- count = 0
- for parameter in parameterlist:
- if count != 0:
- signature += ", "
- count += 1
- dtype = args['parametertypes'].get(parameter, "")
-
- if function_pointer.search(dtype):
- signature += function_pointer.group(1) + parameter + function_pointer.group(3)
- else:
- signature += dtype
-
- if not func_macro:
- signature += ")"
-
- if args.get('typedef') or not args.get('functiontype'):
- print(f".. c:macro:: {args['function']}\n")
-
- if args.get('typedef'):
- self.print_lineno(ln)
- print(" **Typedef**: ", end="")
- self.lineprefix = ""
- self.output_highlight(args.get('purpose', ""))
- print("\n\n**Syntax**\n")
- print(f" ``{signature}``\n")
- else:
- print(f"``{signature}``\n")
- else:
- print(f".. c:function:: {signature}\n")
-
- if not args.get('typedef'):
- self.print_lineno(ln)
- self.lineprefix = " "
- self.output_highlight(args.get('purpose', ""))
- print()
-
- # Put descriptive text into a container (HTML <div>) to help set
- # function prototypes apart
- self.lineprefix = " "
-
- if parameterlist:
- print(".. container:: kernelindent\n")
- print(f"{self.lineprefix}**Parameters**\n")
-
- for parameter in parameterlist:
- parameter_name = Re(r'\[.*').sub('', parameter)
- dtype = args['parametertypes'].get(parameter, "")
-
- if dtype:
- print(f"{self.lineprefix}``{dtype}``")
- else:
- print(f"{self.lineprefix}``{parameter}``")
-
- self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
-
- self.lineprefix = " "
- if parameter_name in parameterdescs and \
- parameterdescs[parameter_name] != KernelDoc.undescribed:
-
- self.output_highlight(parameterdescs[parameter_name])
- print()
- else:
- print(f"{self.lineprefix}*undescribed*\n")
- self.lineprefix = " "
-
- self.out_section(args)
- self.lineprefix = oldprefix
-
- def out_enum(self, fname, name, args):
-
- oldprefix = self.lineprefix
- name = args.get('enum', '')
- parameterlist = args.get('parameterlist', [])
- parameterdescs = args.get('parameterdescs', {})
- ln = args.get('ln', 0)
-
- print(f"\n\n.. c:enum:: {name}\n")
-
- self.print_lineno(ln)
- self.lineprefix = " "
- self.output_highlight(args.get('purpose', ''))
- print()
-
- print(".. container:: kernelindent\n")
- outer = self.lineprefix + " "
- self.lineprefix = outer + " "
- print(f"{outer}**Constants**\n")
-
- for parameter in parameterlist:
- print(f"{outer}``{parameter}``")
-
- if parameterdescs.get(parameter, '') != KernelDoc.undescribed:
- self.output_highlight(parameterdescs[parameter])
- else:
- print(f"{self.lineprefix}*undescribed*\n")
- print()
-
- self.lineprefix = oldprefix
- self.out_section(args)
-
- def out_typedef(self, fname, name, args):
-
- oldprefix = self.lineprefix
- name = args.get('typedef', '')
- ln = args.get('ln', 0)
-
- print(f"\n\n.. c:type:: {name}\n")
-
- self.print_lineno(ln)
- self.lineprefix = " "
-
- self.output_highlight(args.get('purpose', ''))
-
- print()
-
- self.lineprefix = oldprefix
- self.out_section(args)
-
- def out_struct(self, fname, name, args):
-
- name = args.get('struct', "")
- purpose = args.get('purpose', "")
- declaration = args.get('definition', "")
- dtype = args.get('type', "struct")
- ln = args.get('ln', 0)
-
- parameterlist = args.get('parameterlist', [])
- parameterdescs = args.get('parameterdescs', {})
- parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
-
- print(f"\n\n.. c:{dtype}:: {name}\n")
-
- self.print_lineno(ln)
-
- oldprefix = self.lineprefix
- self.lineprefix += " "
-
- self.output_highlight(purpose)
- print()
-
- print(".. container:: kernelindent\n")
- print(f"{self.lineprefix}**Definition**::\n")
-
- self.lineprefix = self.lineprefix + " "
-
- declaration = declaration.replace("\t", self.lineprefix)
-
- print(f"{self.lineprefix}{dtype} {name}" + ' {')
- print(f"{declaration}{self.lineprefix}" + "};\n")
-
- self.lineprefix = " "
- print(f"{self.lineprefix}**Members**\n")
- for parameter in parameterlist:
- if not parameter or parameter.startswith("#"):
- continue
-
- parameter_name = parameter.split("[", maxsplit=1)[0]
-
- if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
- continue
-
- self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
-
- print(f"{self.lineprefix}``{parameter}``")
-
- self.lineprefix = " "
- self.output_highlight(parameterdescs[parameter_name])
- self.lineprefix = " "
-
- print()
-
- print()
-
- self.lineprefix = oldprefix
- self.out_section(args)
-
-
-class ManFormat(OutputFormat):
- """Consts and functions used by man pages output"""
-
- highlights = (
- (type_constant, r"\1"),
- (type_constant2, r"\1"),
- (type_func, r"\\fB\1\\fP"),
- (type_enum, r"\\fI\1\\fP"),
- (type_struct, r"\\fI\1\\fP"),
- (type_typedef, r"\\fI\1\\fP"),
- (type_union, r"\\fI\1\\fP"),
- (type_param, r"\\fI\1\\fP"),
- (type_param_ref, r"\\fI\1\2\\fP"),
- (type_member, r"\\fI\1\2\3\\fP"),
- (type_fallback, r"\\fI\1\\fP")
- )
- blankline = ""
-
- def __init__(self):
- """
- Creates class variables.
-
- Not really mandatory, but it is a good coding style and makes
- pylint happy.
- """
-
- super().__init__()
-
- dt = datetime.now()
- if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
- # use UTC TZ
- to_zone = tz.gettz('UTC')
- dt = dt.astimezone(to_zone)
-
- self.man_date = dt.strftime("%B %Y")
-
- def output_highlight(self, block):
-
- contents = self.highlight_block(block)
-
- if isinstance(contents, list):
- contents = "\n".join(contents)
-
- for line in contents.strip("\n").split("\n"):
- line = Re(r"^\s*").sub("", line)
-
- if line and line[0] == ".":
- print("\\&" + line)
- else:
- print(line)
-
- def out_doc(self, fname, name, args):
- module = args.get('module')
- sectionlist = args.get('sectionlist', [])
- sections = args.get('sections', {})
-
- print(f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX')
-
- for section in sectionlist:
- print(f'.SH "{section}"')
- self.output_highlight(sections.get(section))
-
- def out_function(self, fname, name, args):
- """output function in man"""
-
- parameterlist = args.get('parameterlist', [])
- parameterdescs = args.get('parameterdescs', {})
- sectionlist = args.get('sectionlist', [])
- sections = args.get('sections', {})
-
- print(f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX')
-
- print(".SH NAME")
- print(f"{args['function']} \\- {args['purpose']}")
-
- print(".SH SYNOPSIS")
- if args.get('functiontype', ''):
- print(f'.B "{args['functiontype']}" {args['function']}')
- else:
- print(f'.B "{args['function']}')
-
- count = 0
- parenth = "("
- post = ","
-
- for parameter in parameterlist:
- if count == len(parameterlist) - 1:
- post = ");"
-
- dtype = args['parametertypes'].get(parameter, "")
- if function_pointer.match(dtype):
- # Pointer-to-function
- print(f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"')
- else:
- dtype = Re(r'([^\*])$').sub(r'\1 ', dtype)
-
- print(f'.BI "{parenth}{dtype}" "{post}"')
- count += 1
- parenth = ""
-
- if parameterlist:
- print(".SH ARGUMENTS")
-
- for parameter in parameterlist:
- parameter_name = re.sub(r'\[.*', '', parameter)
-
- print(f'.IP "{parameter}" 12')
- self.output_highlight(parameterdescs.get(parameter_name, ""))
-
- for section in sectionlist:
- print(f'.SH "{section.upper()}"')
- self.output_highlight(sections[section])
-
- def out_enum(self, fname, name, args):
-
- name = args.get('enum', '')
- parameterlist = args.get('parameterlist', [])
- sectionlist = args.get('sectionlist', [])
- sections = args.get('sections', {})
-
- print(f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX')
-
- print(".SH NAME")
- print(f"enum {args['enum']} \\- {args['purpose']}")
-
- print(".SH SYNOPSIS")
- print(f"enum {args['enum']}" + " {")
-
- count = 0
- for parameter in parameterlist:
- print(f'.br\n.BI " {parameter}"')
- if count == len(parameterlist) - 1:
- print("\n};")
- else:
- print(", \n.br")
-
- count += 1
-
- print(".SH Constants")
-
- for parameter in parameterlist:
- parameter_name = Re(r'\[.*').sub('', parameter)
- print(f'.IP "{parameter}" 12')
- self.output_highlight(args['parameterdescs'].get(parameter_name, ""))
-
- for section in sectionlist:
- print(f'.SH "{section}"')
- self.output_highlight(sections[section])
-
- def out_typedef(self, fname, name, args):
- module = args.get('module')
- typedef = args.get('typedef')
- purpose = args.get('purpose')
- sectionlist = args.get('sectionlist', [])
- sections = args.get('sections', {})
-
- print(f'.TH "{module}" 9 "{typedef}" "{self.man_date}" "API Manual" LINUX')
-
- print(".SH NAME")
- print(f"typedef {typedef} \\- {purpose}")
-
- for section in sectionlist:
- print(f'.SH "{section}"')
- self.output_highlight(sections.get(section))
-
- def out_struct(self, fname, name, args):
- module = args.get('module')
- struct_type = args.get('type')
- struct_name = args.get('struct')
- purpose = args.get('purpose')
- definition = args.get('definition')
- sectionlist = args.get('sectionlist', [])
- parameterlist = args.get('parameterlist', [])
- sections = args.get('sections', {})
- parameterdescs = args.get('parameterdescs', {})
-
- print(f'.TH "{module}" 9 "{struct_type} {struct_name}" "{self.man_date}" "API Manual" LINUX')
-
- print(".SH NAME")
- print(f"{struct_type} {struct_name} \\- {purpose}")
-
- # Replace tabs with two spaces and handle newlines
- declaration = definition.replace("\t", " ")
- declaration = Re(r"\n").sub('"\n.br\n.BI "', declaration)
-
- print(".SH SYNOPSIS")
- print(f"{struct_type} {struct_name} " + "{" +"\n.br")
- print(f'.BI "{declaration}\n' + "};\n.br\n")
-
- print(".SH Members")
- for parameter in parameterlist:
- if parameter.startswith("#"):
- continue
-
- parameter_name = re.sub(r"\[.*", "", parameter)
-
- if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
- continue
-
- print(f'.IP "{parameter}" 12')
- self.output_highlight(parameterdescs.get(parameter_name))
-
- for section in sectionlist:
- print(f'.SH "{section}"')
- self.output_highlight(sections.get(section))
-
-
-# Command line interface
-
+from kdoc_files import KernelFiles # pylint: disable=C0413
+from kdoc_output import RestFormat, ManFormat # pylint: disable=C0413
DESC = """
Read C language source or header FILEs, extract embedded documentation comments,
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
new file mode 100755
index 000000000000..d080440caa1c
--- /dev/null
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -0,0 +1,735 @@
+#!/usr/bin/env python3
+# pylint: disable=C0301,R0911,R0912,R0913,R0914,R0915,R0917
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+# TODO: implement warning filtering
+
+"""
+Implement output filters to print kernel-doc documentation.
+
+The implementation uses a virtual base class (OutputFormat) which
+contains a dispatches to virtual methods, and some code to filter
+out output messages.
+
+The actual implementation is done on one separate class per each type
+of output. Currently, there are output classes for ReST and man/troff.
+"""
+
+import os
+import re
+from datetime import datetime
+
+from dateutil import tz
+
+from kdoc_parser import KernelDoc, type_param
+from kdoc_re import Re
+
+
+function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
+
+# match expressions used to find embedded type information
+type_constant = Re(r"\b``([^\`]+)``\b", cache=False)
+type_constant2 = Re(r"\%([-_*\w]+)", cache=False)
+type_func = Re(r"(\w+)\(\)", cache=False)
+type_param_ref = Re(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+
+# Special RST handling for func ptr params
+type_fp_param = Re(r"\@(\w+)\(\)", cache=False)
+
+# Special RST handling for structs with func ptr params
+type_fp_param2 = Re(r"\@(\w+->\S+)\(\)", cache=False)
+
+type_env = Re(r"(\$\w+)", cache=False)
+type_enum = Re(r"\&(enum\s*([_\w]+))", cache=False)
+type_struct = Re(r"\&(struct\s*([_\w]+))", cache=False)
+type_typedef = Re(r"\&(typedef\s*([_\w]+))", cache=False)
+type_union = Re(r"\&(union\s*([_\w]+))", cache=False)
+type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
+type_fallback = Re(r"\&([_\w]+)", cache=False)
+type_member_func = type_member + Re(r"\(\)", cache=False)
+
+
+class OutputFormat:
+ # output mode.
+ OUTPUT_ALL = 0 # output all symbols and doc sections
+ OUTPUT_INCLUDE = 1 # output only specified symbols
+ OUTPUT_EXPORTED = 2 # output exported symbols
+ OUTPUT_INTERNAL = 3 # output non-exported symbols
+
+ # Virtual member to be overriden at the inherited classes
+ highlights = []
+
+ def __init__(self):
+ """Declare internal vars and set mode to OUTPUT_ALL"""
+
+ self.out_mode = self.OUTPUT_ALL
+ self.enable_lineno = None
+ self.nosymbol = {}
+ self.symbol = None
+ self.function_table = set()
+ self.config = None
+
+ def set_config(self, config):
+ self.config = config
+
+ def set_filter(self, export, internal, symbol, nosymbol, function_table,
+ enable_lineno):
+ """
+ Initialize filter variables according with the requested mode.
+
+ Only one choice is valid between export, internal and symbol.
+
+ The nosymbol filter can be used on all modes.
+ """
+
+ self.enable_lineno = enable_lineno
+
+ if symbol:
+ self.out_mode = self.OUTPUT_INCLUDE
+ function_table = symbol
+ elif export:
+ self.out_mode = self.OUTPUT_EXPORTED
+ elif internal:
+ self.out_mode = self.OUTPUT_INTERNAL
+ else:
+ self.out_mode = self.OUTPUT_ALL
+
+ if nosymbol:
+ self.nosymbol = set(nosymbol)
+
+ if function_table:
+ self.function_table = function_table
+
+ def highlight_block(self, block):
+ """
+ Apply the RST highlights to a sub-block of text.
+ """
+
+ for r, sub in self.highlights:
+ block = r.sub(sub, block)
+
+ return block
+
+ def check_doc(self, name):
+ """Check if DOC should be output"""
+
+ if self.out_mode == self.OUTPUT_ALL:
+ return True
+
+ if self.out_mode == self.OUTPUT_INCLUDE:
+ if name in self.nosymbol:
+ return False
+
+ if name in self.function_table:
+ return True
+
+ return False
+
+ def check_declaration(self, dtype, name):
+ if name in self.nosymbol:
+ return False
+
+ if self.out_mode == self.OUTPUT_ALL:
+ return True
+
+ if self.out_mode in [self.OUTPUT_INCLUDE, self.OUTPUT_EXPORTED]:
+ if name in self.function_table:
+ return True
+
+ if self.out_mode == self.OUTPUT_INTERNAL:
+ if dtype != "function":
+ return True
+
+ if name not in self.function_table:
+ return True
+
+ return False
+
+ def check_function(self, fname, name, args):
+ return True
+
+ def check_enum(self, fname, name, args):
+ return True
+
+ def check_typedef(self, fname, name, args):
+ return True
+
+ def msg(self, fname, name, args):
+
+ dtype = args.get('type', "")
+
+ if dtype == "doc":
+ self.out_doc(fname, name, args)
+ return False
+
+ if not self.check_declaration(dtype, name):
+ return False
+
+ if dtype == "function":
+ self.out_function(fname, name, args)
+ return False
+
+ if dtype == "enum":
+ self.out_enum(fname, name, args)
+ return False
+
+ if dtype == "typedef":
+ self.out_typedef(fname, name, args)
+ return False
+
+ if dtype in ["struct", "union"]:
+ self.out_struct(fname, name, args)
+ return False
+
+ # Warn if some type requires an output logic
+ self.config.log.warning("doesn't now how to output '%s' block",
+ dtype)
+
+ return True
+
+ # Virtual methods to be overridden by inherited classes
+ def out_doc(self, fname, name, args):
+ pass
+
+ def out_function(self, fname, name, args):
+ pass
+
+ def out_enum(self, fname, name, args):
+ pass
+
+ def out_typedef(self, fname, name, args):
+ pass
+
+ def out_struct(self, fname, name, args):
+ pass
+
+
+class RestFormat(OutputFormat):
+ # """Consts and functions used by ReST output"""
+
+ highlights = [
+ (type_constant, r"``\1``"),
+ (type_constant2, r"``\1``"),
+
+ # Note: need to escape () to avoid func matching later
+ (type_member_func, r":c:type:`\1\2\3\\(\\) <\1>`"),
+ (type_member, r":c:type:`\1\2\3 <\1>`"),
+ (type_fp_param, r"**\1\\(\\)**"),
+ (type_fp_param2, r"**\1\\(\\)**"),
+ (type_func, r"\1()"),
+ (type_enum, r":c:type:`\1 <\2>`"),
+ (type_struct, r":c:type:`\1 <\2>`"),
+ (type_typedef, r":c:type:`\1 <\2>`"),
+ (type_union, r":c:type:`\1 <\2>`"),
+
+ # in rst this can refer to any type
+ (type_fallback, r":c:type:`\1`"),
+ (type_param_ref, r"**\1\2**")
+ ]
+ blankline = "\n"
+
+ sphinx_literal = Re(r'^[^.].*::$', cache=False)
+ sphinx_cblock = Re(r'^\.\.\ +code-block::', cache=False)
+
+ def __init__(self):
+ """
+ Creates class variables.
+
+ Not really mandatory, but it is a good coding style and makes
+ pylint happy.
+ """
+
+ super().__init__()
+ self.lineprefix = ""
+
+ def print_lineno(self, ln):
+ """Outputs a line number"""
+
+ if self.enable_lineno and ln:
+ print(f".. LINENO {ln}")
+
+ def output_highlight(self, args):
+ input_text = args
+ output = ""
+ in_literal = False
+ litprefix = ""
+ block = ""
+
+ for line in input_text.strip("\n").split("\n"):
+
+ # If we're in a literal block, see if we should drop out of it.
+ # Otherwise, pass the line straight through unmunged.
+ if in_literal:
+ if line.strip(): # If the line is not blank
+ # If this is the first non-blank line in a literal block,
+ # figure out the proper indent.
+ if not litprefix:
+ r = Re(r'^(\s*)')
+ if r.match(line):
+ litprefix = '^' + r.group(1)
+ else:
+ litprefix = ""
+
+ output += line + "\n"
+ elif not Re(litprefix).match(line):
+ in_literal = False
+ else:
+ output += line + "\n"
+ else:
+ output += line + "\n"
+
+ # Not in a literal block (or just dropped out)
+ if not in_literal:
+ block += line + "\n"
+ if self.sphinx_literal.match(line) or self.sphinx_cblock.match(line):
+ in_literal = True
+ litprefix = ""
+ output += self.highlight_block(block)
+ block = ""
+
+ # Handle any remaining block
+ if block:
+ output += self.highlight_block(block)
+
+ # Print the output with the line prefix
+ for line in output.strip("\n").split("\n"):
+ print(self.lineprefix + line)
+
+ def out_section(self, args, out_reference=False):
+ """
+ Outputs a block section.
+
+ This could use some work; it's used to output the DOC: sections, and
+ starts by putting out the name of the doc section itself, but that
+ tends to duplicate a header already in the template file.
+ """
+
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+ section_start_lines = args.get('section_start_lines', {})
+
+ for section in sectionlist:
+ # Skip sections that are in the nosymbol_table
+ if section in self.nosymbol:
+ continue
+
+ if not self.out_mode == self.OUTPUT_INCLUDE:
+ if out_reference:
+ print(f".. _{section}:\n")
+
+ if not self.symbol:
+ print(f'{self.lineprefix}**{section}**\n')
+
+ self.print_lineno(section_start_lines.get(section, 0))
+ self.output_highlight(sections[section])
+ print()
+ print()
+
+ def out_doc(self, fname, name, args):
+ if not self.check_doc(name):
+ return
+
+ self.out_section(args, out_reference=True)
+
+ def out_function(self, fname, name, args):
+
+ oldprefix = self.lineprefix
+ signature = ""
+
+ func_macro = args.get('func_macro', False)
+ if func_macro:
+ signature = args['function']
+ else:
+ if args.get('functiontype'):
+ signature = args['functiontype'] + " "
+ signature += args['function'] + " ("
+
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
+
+ ln = args.get('ln', 0)
+
+ count = 0
+ for parameter in parameterlist:
+ if count != 0:
+ signature += ", "
+ count += 1
+ dtype = args['parametertypes'].get(parameter, "")
+
+ if function_pointer.search(dtype):
+ signature += function_pointer.group(1) + parameter + function_pointer.group(3)
+ else:
+ signature += dtype
+
+ if not func_macro:
+ signature += ")"
+
+ if args.get('typedef') or not args.get('functiontype'):
+ print(f".. c:macro:: {args['function']}\n")
+
+ if args.get('typedef'):
+ self.print_lineno(ln)
+ print(" **Typedef**: ", end="")
+ self.lineprefix = ""
+ self.output_highlight(args.get('purpose', ""))
+ print("\n\n**Syntax**\n")
+ print(f" ``{signature}``\n")
+ else:
+ print(f"``{signature}``\n")
+ else:
+ print(f".. c:function:: {signature}\n")
+
+ if not args.get('typedef'):
+ self.print_lineno(ln)
+ self.lineprefix = " "
+ self.output_highlight(args.get('purpose', ""))
+ print()
+
+ # Put descriptive text into a container (HTML <div>) to help set
+ # function prototypes apart
+ self.lineprefix = " "
+
+ if parameterlist:
+ print(".. container:: kernelindent\n")
+ print(f"{self.lineprefix}**Parameters**\n")
+
+ for parameter in parameterlist:
+ parameter_name = Re(r'\[.*').sub('', parameter)
+ dtype = args['parametertypes'].get(parameter, "")
+
+ if dtype:
+ print(f"{self.lineprefix}``{dtype}``")
+ else:
+ print(f"{self.lineprefix}``{parameter}``")
+
+ self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
+
+ self.lineprefix = " "
+ if parameter_name in parameterdescs and \
+ parameterdescs[parameter_name] != KernelDoc.undescribed:
+
+ self.output_highlight(parameterdescs[parameter_name])
+ print()
+ else:
+ print(f"{self.lineprefix}*undescribed*\n")
+ self.lineprefix = " "
+
+ self.out_section(args)
+ self.lineprefix = oldprefix
+
+ def out_enum(self, fname, name, args):
+
+ oldprefix = self.lineprefix
+ name = args.get('enum', '')
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ ln = args.get('ln', 0)
+
+ print(f"\n\n.. c:enum:: {name}\n")
+
+ self.print_lineno(ln)
+ self.lineprefix = " "
+ self.output_highlight(args.get('purpose', ''))
+ print()
+
+ print(".. container:: kernelindent\n")
+ outer = self.lineprefix + " "
+ self.lineprefix = outer + " "
+ print(f"{outer}**Constants**\n")
+
+ for parameter in parameterlist:
+ print(f"{outer}``{parameter}``")
+
+ if parameterdescs.get(parameter, '') != KernelDoc.undescribed:
+ self.output_highlight(parameterdescs[parameter])
+ else:
+ print(f"{self.lineprefix}*undescribed*\n")
+ print()
+
+ self.lineprefix = oldprefix
+ self.out_section(args)
+
+ def out_typedef(self, fname, name, args):
+
+ oldprefix = self.lineprefix
+ name = args.get('typedef', '')
+ ln = args.get('ln', 0)
+
+ print(f"\n\n.. c:type:: {name}\n")
+
+ self.print_lineno(ln)
+ self.lineprefix = " "
+
+ self.output_highlight(args.get('purpose', ''))
+
+ print()
+
+ self.lineprefix = oldprefix
+ self.out_section(args)
+
+ def out_struct(self, fname, name, args):
+
+ name = args.get('struct', "")
+ purpose = args.get('purpose', "")
+ declaration = args.get('definition', "")
+ dtype = args.get('type', "struct")
+ ln = args.get('ln', 0)
+
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
+
+ print(f"\n\n.. c:{dtype}:: {name}\n")
+
+ self.print_lineno(ln)
+
+ oldprefix = self.lineprefix
+ self.lineprefix += " "
+
+ self.output_highlight(purpose)
+ print()
+
+ print(".. container:: kernelindent\n")
+ print(f"{self.lineprefix}**Definition**::\n")
+
+ self.lineprefix = self.lineprefix + " "
+
+ declaration = declaration.replace("\t", self.lineprefix)
+
+ print(f"{self.lineprefix}{dtype} {name}" + ' {')
+ print(f"{declaration}{self.lineprefix}" + "};\n")
+
+ self.lineprefix = " "
+ print(f"{self.lineprefix}**Members**\n")
+ for parameter in parameterlist:
+ if not parameter or parameter.startswith("#"):
+ continue
+
+ parameter_name = parameter.split("[", maxsplit=1)[0]
+
+ if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
+ continue
+
+ self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
+
+ print(f"{self.lineprefix}``{parameter}``")
+
+ self.lineprefix = " "
+ self.output_highlight(parameterdescs[parameter_name])
+ self.lineprefix = " "
+
+ print()
+
+ print()
+
+ self.lineprefix = oldprefix
+ self.out_section(args)
+
+
+class ManFormat(OutputFormat):
+ """Consts and functions used by man pages output"""
+
+ highlights = (
+ (type_constant, r"\1"),
+ (type_constant2, r"\1"),
+ (type_func, r"\\fB\1\\fP"),
+ (type_enum, r"\\fI\1\\fP"),
+ (type_struct, r"\\fI\1\\fP"),
+ (type_typedef, r"\\fI\1\\fP"),
+ (type_union, r"\\fI\1\\fP"),
+ (type_param, r"\\fI\1\\fP"),
+ (type_param_ref, r"\\fI\1\2\\fP"),
+ (type_member, r"\\fI\1\2\3\\fP"),
+ (type_fallback, r"\\fI\1\\fP")
+ )
+ blankline = ""
+
+ def __init__(self):
+ """
+ Creates class variables.
+
+ Not really mandatory, but it is a good coding style and makes
+ pylint happy.
+ """
+
+ super().__init__()
+
+ dt = datetime.now()
+ if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
+ # use UTC TZ
+ to_zone = tz.gettz('UTC')
+ dt = dt.astimezone(to_zone)
+
+ self.man_date = dt.strftime("%B %Y")
+
+ def output_highlight(self, block):
+
+ contents = self.highlight_block(block)
+
+ if isinstance(contents, list):
+ contents = "\n".join(contents)
+
+ for line in contents.strip("\n").split("\n"):
+ line = Re(r"^\s*").sub("", line)
+
+ if line and line[0] == ".":
+ print("\\&" + line)
+ else:
+ print(line)
+
+ def out_doc(self, fname, name, args):
+ module = args.get('module')
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX')
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections.get(section))
+
+ def out_function(self, fname, name, args):
+ """output function in man"""
+
+ parameterlist = args.get('parameterlist', [])
+ parameterdescs = args.get('parameterdescs', {})
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"{args['function']} \\- {args['purpose']}")
+
+ print(".SH SYNOPSIS")
+ if args.get('functiontype', ''):
+ print(f'.B "{args['functiontype']}" {args['function']}')
+ else:
+ print(f'.B "{args['function']}')
+
+ count = 0
+ parenth = "("
+ post = ","
+
+ for parameter in parameterlist:
+ if count == len(parameterlist) - 1:
+ post = ");"
+
+ dtype = args['parametertypes'].get(parameter, "")
+ if function_pointer.match(dtype):
+ # Pointer-to-function
+ print(f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"')
+ else:
+ dtype = Re(r'([^\*])$').sub(r'\1 ', dtype)
+
+ print(f'.BI "{parenth}{dtype}" "{post}"')
+ count += 1
+ parenth = ""
+
+ if parameterlist:
+ print(".SH ARGUMENTS")
+
+ for parameter in parameterlist:
+ parameter_name = re.sub(r'\[.*', '', parameter)
+
+ print(f'.IP "{parameter}" 12')
+ self.output_highlight(parameterdescs.get(parameter_name, ""))
+
+ for section in sectionlist:
+ print(f'.SH "{section.upper()}"')
+ self.output_highlight(sections[section])
+
+ def out_enum(self, fname, name, args):
+
+ name = args.get('enum', '')
+ parameterlist = args.get('parameterlist', [])
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"enum {args['enum']} \\- {args['purpose']}")
+
+ print(".SH SYNOPSIS")
+ print(f"enum {args['enum']}" + " {")
+
+ count = 0
+ for parameter in parameterlist:
+ print(f'.br\n.BI " {parameter}"')
+ if count == len(parameterlist) - 1:
+ print("\n};")
+ else:
+ print(", \n.br")
+
+ count += 1
+
+ print(".SH Constants")
+
+ for parameter in parameterlist:
+ parameter_name = Re(r'\[.*').sub('', parameter)
+ print(f'.IP "{parameter}" 12')
+ self.output_highlight(args['parameterdescs'].get(parameter_name, ""))
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections[section])
+
+ def out_typedef(self, fname, name, args):
+ module = args.get('module')
+ typedef = args.get('typedef')
+ purpose = args.get('purpose')
+ sectionlist = args.get('sectionlist', [])
+ sections = args.get('sections', {})
+
+ print(f'.TH "{module}" 9 "{typedef}" "{self.man_date}" "API Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"typedef {typedef} \\- {purpose}")
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections.get(section))
+
+ def out_struct(self, fname, name, args):
+ module = args.get('module')
+ struct_type = args.get('type')
+ struct_name = args.get('struct')
+ purpose = args.get('purpose')
+ definition = args.get('definition')
+ sectionlist = args.get('sectionlist', [])
+ parameterlist = args.get('parameterlist', [])
+ sections = args.get('sections', {})
+ parameterdescs = args.get('parameterdescs', {})
+
+ print(f'.TH "{module}" 9 "{struct_type} {struct_name}" "{self.man_date}" "API Manual" LINUX')
+
+ print(".SH NAME")
+ print(f"{struct_type} {struct_name} \\- {purpose}")
+
+ # Replace tabs with two spaces and handle newlines
+ declaration = definition.replace("\t", " ")
+ declaration = Re(r"\n").sub('"\n.br\n.BI "', declaration)
+
+ print(".SH SYNOPSIS")
+ print(f"{struct_type} {struct_name} " + "{" + "\n.br")
+ print(f'.BI "{declaration}\n' + "};\n.br\n")
+
+ print(".SH Members")
+ for parameter in parameterlist:
+ if parameter.startswith("#"):
+ continue
+
+ parameter_name = re.sub(r"\[.*", "", parameter)
+
+ if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
+ continue
+
+ print(f'.IP "{parameter}" 12')
+ self.output_highlight(parameterdescs.get(parameter_name))
+
+ for section in sectionlist:
+ print(f'.SH "{section}"')
+ self.output_highlight(sections.get(section))
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 17/39] scripts/kernel-doc.py: convert message output to an interactor
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (15 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 16/39] scripts/kernel-doc.py: move output classes " Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 18/39] scripts/kernel-doc.py: move file lists to the parser function Mauro Carvalho Chehab
` (22 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Instead of directly printing output messages, change kdoc classes
to return an interactor with the output message, letting the
actual display to happen at the command-line command.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 9 +-
scripts/lib/kdoc/kdoc_files.py | 15 ++-
scripts/lib/kdoc/kdoc_output.py | 171 ++++++++++++++++----------------
3 files changed, 104 insertions(+), 91 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 0596c711d448..6c3179a2da65 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -208,9 +208,12 @@ def main():
kfiles.parse()
- kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
- internal=args.internal, symbol=args.symbol,
- nosymbol=args.nosymbol)
+ for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
+ internal=args.internal, symbol=args.symbol,
+ nosymbol=args.nosymbol):
+ msg = t[1]
+ if msg:
+ print(msg)
# Call main method
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 76dd53611c08..434fc66a9dad 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -228,9 +228,10 @@ class KernelFiles():
def out_msg(self, fname, name, arg):
"""
- Output messages from a file name using the output style filtering.
+ Return output messages from a file name using the output style
+ filtering.
- If output type was not handled by the syler, return False.
+ If output type was not handled by the syler, return None.
"""
# NOTE: we can add rules here to filter out unwanted parts,
@@ -241,7 +242,8 @@ class KernelFiles():
def msg(self, enable_lineno=False, export=False, internal=False,
symbol=None, nosymbol=None):
"""
- Interacts over the kernel-doc results and output messages.
+ Interacts over the kernel-doc results and output messages,
+ returning kernel-doc markups on each interaction
"""
function_table = self.config.function_table
@@ -260,10 +262,15 @@ class KernelFiles():
function_table, enable_lineno)
for fname, arg_tuple in self.results:
+ msg = ""
for name, arg in arg_tuple:
- if self.out_msg(fname, name, arg):
+ msg += self.out_msg(fname, name, arg)
+
+ if msg is None:
ln = arg.get("ln", 0)
dtype = arg.get('type', "")
self.config.log.warning("%s:%d Can't handle %s",
fname, ln, dtype)
+ if msg:
+ yield fname, msg
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index d080440caa1c..91f6e356d03d 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -70,6 +70,8 @@ class OutputFormat:
self.function_table = set()
self.config = None
+ self.data = ""
+
def set_config(self, config):
self.config = config
@@ -156,37 +158,38 @@ class OutputFormat:
return True
def msg(self, fname, name, args):
+ self.data = ""
dtype = args.get('type', "")
if dtype == "doc":
self.out_doc(fname, name, args)
- return False
+ return self.data
if not self.check_declaration(dtype, name):
- return False
+ return self.data
if dtype == "function":
self.out_function(fname, name, args)
- return False
+ return self.data
if dtype == "enum":
self.out_enum(fname, name, args)
- return False
+ return self.data
if dtype == "typedef":
self.out_typedef(fname, name, args)
- return False
+ return self.data
if dtype in ["struct", "union"]:
self.out_struct(fname, name, args)
- return False
+ return self.data
# Warn if some type requires an output logic
self.config.log.warning("doesn't now how to output '%s' block",
dtype)
- return True
+ return None
# Virtual methods to be overridden by inherited classes
def out_doc(self, fname, name, args):
@@ -247,7 +250,7 @@ class RestFormat(OutputFormat):
"""Outputs a line number"""
if self.enable_lineno and ln:
- print(f".. LINENO {ln}")
+ self.data += f".. LINENO {ln}\n"
def output_highlight(self, args):
input_text = args
@@ -294,7 +297,7 @@ class RestFormat(OutputFormat):
# Print the output with the line prefix
for line in output.strip("\n").split("\n"):
- print(self.lineprefix + line)
+ self.data += self.lineprefix + line + "\n"
def out_section(self, args, out_reference=False):
"""
@@ -316,15 +319,15 @@ class RestFormat(OutputFormat):
if not self.out_mode == self.OUTPUT_INCLUDE:
if out_reference:
- print(f".. _{section}:\n")
+ self.data += f".. _{section}:\n\n"
if not self.symbol:
- print(f'{self.lineprefix}**{section}**\n')
+ self.data += f'{self.lineprefix}**{section}**\n\n'
self.print_lineno(section_start_lines.get(section, 0))
self.output_highlight(sections[section])
- print()
- print()
+ self.data += "\n"
+ self.data += "\n"
def out_doc(self, fname, name, args):
if not self.check_doc(name):
@@ -367,42 +370,42 @@ class RestFormat(OutputFormat):
signature += ")"
if args.get('typedef') or not args.get('functiontype'):
- print(f".. c:macro:: {args['function']}\n")
+ self.data += f".. c:macro:: {args['function']}\n\n"
if args.get('typedef'):
self.print_lineno(ln)
- print(" **Typedef**: ", end="")
+ self.data += " **Typedef**: "
self.lineprefix = ""
self.output_highlight(args.get('purpose', ""))
- print("\n\n**Syntax**\n")
- print(f" ``{signature}``\n")
+ self.data += "\n\n**Syntax**\n\n"
+ self.data += f" ``{signature}``\n\n"
else:
- print(f"``{signature}``\n")
+ self.data += f"``{signature}``\n\n"
else:
- print(f".. c:function:: {signature}\n")
+ self.data += f".. c:function:: {signature}\n\n"
if not args.get('typedef'):
self.print_lineno(ln)
self.lineprefix = " "
self.output_highlight(args.get('purpose', ""))
- print()
+ self.data += "\n"
# Put descriptive text into a container (HTML <div>) to help set
# function prototypes apart
self.lineprefix = " "
if parameterlist:
- print(".. container:: kernelindent\n")
- print(f"{self.lineprefix}**Parameters**\n")
+ self.data += ".. container:: kernelindent\n\n"
+ self.data += f"{self.lineprefix}**Parameters**\n\n"
for parameter in parameterlist:
parameter_name = Re(r'\[.*').sub('', parameter)
dtype = args['parametertypes'].get(parameter, "")
if dtype:
- print(f"{self.lineprefix}``{dtype}``")
+ self.data += f"{self.lineprefix}``{dtype}``\n"
else:
- print(f"{self.lineprefix}``{parameter}``")
+ self.data += f"{self.lineprefix}``{parameter}``\n"
self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
@@ -411,9 +414,9 @@ class RestFormat(OutputFormat):
parameterdescs[parameter_name] != KernelDoc.undescribed:
self.output_highlight(parameterdescs[parameter_name])
- print()
+ self.data += "\n"
else:
- print(f"{self.lineprefix}*undescribed*\n")
+ self.data += f"{self.lineprefix}*undescribed*\n\n"
self.lineprefix = " "
self.out_section(args)
@@ -427,26 +430,26 @@ class RestFormat(OutputFormat):
parameterdescs = args.get('parameterdescs', {})
ln = args.get('ln', 0)
- print(f"\n\n.. c:enum:: {name}\n")
+ self.data += f"\n\n.. c:enum:: {name}\n\n"
self.print_lineno(ln)
self.lineprefix = " "
self.output_highlight(args.get('purpose', ''))
- print()
+ self.data += "\n"
- print(".. container:: kernelindent\n")
+ self.data += ".. container:: kernelindent\n\n"
outer = self.lineprefix + " "
self.lineprefix = outer + " "
- print(f"{outer}**Constants**\n")
+ self.data += f"{outer}**Constants**\n\n"
for parameter in parameterlist:
- print(f"{outer}``{parameter}``")
+ self.data += f"{outer}``{parameter}``\n"
if parameterdescs.get(parameter, '') != KernelDoc.undescribed:
self.output_highlight(parameterdescs[parameter])
else:
- print(f"{self.lineprefix}*undescribed*\n")
- print()
+ self.data += f"{self.lineprefix}*undescribed*\n\n"
+ self.data += "\n"
self.lineprefix = oldprefix
self.out_section(args)
@@ -457,14 +460,14 @@ class RestFormat(OutputFormat):
name = args.get('typedef', '')
ln = args.get('ln', 0)
- print(f"\n\n.. c:type:: {name}\n")
+ self.data += f"\n\n.. c:type:: {name}\n\n"
self.print_lineno(ln)
self.lineprefix = " "
self.output_highlight(args.get('purpose', ''))
- print()
+ self.data += "\n"
self.lineprefix = oldprefix
self.out_section(args)
@@ -481,7 +484,7 @@ class RestFormat(OutputFormat):
parameterdescs = args.get('parameterdescs', {})
parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
- print(f"\n\n.. c:{dtype}:: {name}\n")
+ self.data += f"\n\n.. c:{dtype}:: {name}\n\n"
self.print_lineno(ln)
@@ -489,20 +492,20 @@ class RestFormat(OutputFormat):
self.lineprefix += " "
self.output_highlight(purpose)
- print()
+ self.data += "\n"
- print(".. container:: kernelindent\n")
- print(f"{self.lineprefix}**Definition**::\n")
+ self.data += ".. container:: kernelindent\n\n"
+ self.data += f"{self.lineprefix}**Definition**::\n\n"
self.lineprefix = self.lineprefix + " "
declaration = declaration.replace("\t", self.lineprefix)
- print(f"{self.lineprefix}{dtype} {name}" + ' {')
- print(f"{declaration}{self.lineprefix}" + "};\n")
+ self.data += f"{self.lineprefix}{dtype} {name}" + ' {' + "\n"
+ self.data += f"{declaration}{self.lineprefix}" + "};\n\n"
self.lineprefix = " "
- print(f"{self.lineprefix}**Members**\n")
+ self.data += f"{self.lineprefix}**Members**\n\n"
for parameter in parameterlist:
if not parameter or parameter.startswith("#"):
continue
@@ -514,15 +517,15 @@ class RestFormat(OutputFormat):
self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
- print(f"{self.lineprefix}``{parameter}``")
+ self.data += f"{self.lineprefix}``{parameter}``\n"
self.lineprefix = " "
self.output_highlight(parameterdescs[parameter_name])
self.lineprefix = " "
- print()
+ self.data += "\n"
- print()
+ self.data += "\n"
self.lineprefix = oldprefix
self.out_section(args)
@@ -575,19 +578,19 @@ class ManFormat(OutputFormat):
line = Re(r"^\s*").sub("", line)
if line and line[0] == ".":
- print("\\&" + line)
+ self.data += "\\&" + line + "\n"
else:
- print(line)
+ self.data += line + "\n"
def out_doc(self, fname, name, args):
module = args.get('module')
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- print(f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX')
+ self.data += f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX' + "\n"
for section in sectionlist:
- print(f'.SH "{section}"')
+ self.data += f'.SH "{section}"' + "\n"
self.output_highlight(sections.get(section))
def out_function(self, fname, name, args):
@@ -598,16 +601,16 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- print(f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX')
+ self.data += f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX' + "\n"
- print(".SH NAME")
- print(f"{args['function']} \\- {args['purpose']}")
+ self.data += ".SH NAME\n"
+ self.data += f"{args['function']} \\- {args['purpose']}\n"
- print(".SH SYNOPSIS")
+ self.data += ".SH SYNOPSIS\n"
if args.get('functiontype', ''):
- print(f'.B "{args['functiontype']}" {args['function']}')
+ self.data += f'.B "{args['functiontype']}" {args['function']}' + "\n"
else:
- print(f'.B "{args['function']}')
+ self.data += f'.B "{args['function']}' + "\n"
count = 0
parenth = "("
@@ -620,25 +623,25 @@ class ManFormat(OutputFormat):
dtype = args['parametertypes'].get(parameter, "")
if function_pointer.match(dtype):
# Pointer-to-function
- print(f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"')
+ self.data += f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"' + "\n"
else:
dtype = Re(r'([^\*])$').sub(r'\1 ', dtype)
- print(f'.BI "{parenth}{dtype}" "{post}"')
+ self.data += f'.BI "{parenth}{dtype}" "{post}"' + "\n"
count += 1
parenth = ""
if parameterlist:
- print(".SH ARGUMENTS")
+ self.data += ".SH ARGUMENTS\n"
for parameter in parameterlist:
parameter_name = re.sub(r'\[.*', '', parameter)
- print(f'.IP "{parameter}" 12')
+ self.data += f'.IP "{parameter}" 12' + "\n"
self.output_highlight(parameterdescs.get(parameter_name, ""))
for section in sectionlist:
- print(f'.SH "{section.upper()}"')
+ self.data += f'.SH "{section.upper()}"' + "\n"
self.output_highlight(sections[section])
def out_enum(self, fname, name, args):
@@ -648,33 +651,33 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- print(f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX')
+ self.data += f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX' + "\n"
- print(".SH NAME")
- print(f"enum {args['enum']} \\- {args['purpose']}")
+ self.data += ".SH NAME\n"
+ self.data += f"enum {args['enum']} \\- {args['purpose']}\n"
- print(".SH SYNOPSIS")
- print(f"enum {args['enum']}" + " {")
+ self.data += ".SH SYNOPSIS\n"
+ self.data += f"enum {args['enum']}" + " {\n"
count = 0
for parameter in parameterlist:
- print(f'.br\n.BI " {parameter}"')
+ self.data += f'.br\n.BI " {parameter}"' + "\n"
if count == len(parameterlist) - 1:
- print("\n};")
+ self.data += "\n};\n"
else:
- print(", \n.br")
+ self.data += ", \n.br\n"
count += 1
- print(".SH Constants")
+ self.data += ".SH Constants\n"
for parameter in parameterlist:
parameter_name = Re(r'\[.*').sub('', parameter)
- print(f'.IP "{parameter}" 12')
+ self.data += f'.IP "{parameter}" 12' + "\n"
self.output_highlight(args['parameterdescs'].get(parameter_name, ""))
for section in sectionlist:
- print(f'.SH "{section}"')
+ self.data += f'.SH "{section}"' + "\n"
self.output_highlight(sections[section])
def out_typedef(self, fname, name, args):
@@ -684,13 +687,13 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- print(f'.TH "{module}" 9 "{typedef}" "{self.man_date}" "API Manual" LINUX')
+ self.data += f'.TH "{module}" 9 "{typedef}" "{self.man_date}" "API Manual" LINUX' + "\n"
- print(".SH NAME")
- print(f"typedef {typedef} \\- {purpose}")
+ self.data += ".SH NAME\n"
+ self.data += f"typedef {typedef} \\- {purpose}\n"
for section in sectionlist:
- print(f'.SH "{section}"')
+ self.data += f'.SH "{section}"' + "\n"
self.output_highlight(sections.get(section))
def out_struct(self, fname, name, args):
@@ -704,20 +707,20 @@ class ManFormat(OutputFormat):
sections = args.get('sections', {})
parameterdescs = args.get('parameterdescs', {})
- print(f'.TH "{module}" 9 "{struct_type} {struct_name}" "{self.man_date}" "API Manual" LINUX')
+ self.data += f'.TH "{module}" 9 "{struct_type} {struct_name}" "{self.man_date}" "API Manual" LINUX' + "\n"
- print(".SH NAME")
- print(f"{struct_type} {struct_name} \\- {purpose}")
+ self.data += ".SH NAME\n"
+ self.data += f"{struct_type} {struct_name} \\- {purpose}\n"
# Replace tabs with two spaces and handle newlines
declaration = definition.replace("\t", " ")
declaration = Re(r"\n").sub('"\n.br\n.BI "', declaration)
- print(".SH SYNOPSIS")
- print(f"{struct_type} {struct_name} " + "{" + "\n.br")
- print(f'.BI "{declaration}\n' + "};\n.br\n")
+ self.data += ".SH SYNOPSIS\n"
+ self.data += f"{struct_type} {struct_name} " + "{" + "\n.br\n"
+ self.data += f'.BI "{declaration}\n' + "};\n.br\n\n"
- print(".SH Members")
+ self.data += ".SH Members\n"
for parameter in parameterlist:
if parameter.startswith("#"):
continue
@@ -727,9 +730,9 @@ class ManFormat(OutputFormat):
if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
continue
- print(f'.IP "{parameter}" 12')
+ self.data += f'.IP "{parameter}" 12' + "\n"
self.output_highlight(parameterdescs.get(parameter_name))
for section in sectionlist:
- print(f'.SH "{section}"')
+ self.data += f'.SH "{section}"' + "\n"
self.output_highlight(sections.get(section))
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 18/39] scripts/kernel-doc.py: move file lists to the parser function
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (16 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 17/39] scripts/kernel-doc.py: convert message output to an interactor Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 19/39] scripts/kernel-doc.py: implement support for -no-doc-sections Mauro Carvalho Chehab
` (21 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Instead of setting file lists at __init__ time, move it to
the actual parsing function. This allows adding more files
to be parsed in real time, by calling parse function multiple
times.
With the new way, the export_files logic was rewritten to
avoid parsing twice EXPORT_SYMBOL for partial matches.
Please notice that, with this logic, it can still read the
same file twice when export_file is used.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 7 +++----
scripts/lib/kdoc/kdoc_files.py | 37 ++++++++++++++++------------------
2 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 6c3179a2da65..a687a7abb3b9 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -199,14 +199,13 @@ def main():
else:
out_style = RestFormat()
- kfiles = KernelFiles(files=args.files, verbose=args.verbose,
+ kfiles = KernelFiles(verbose=args.verbose,
out_style=out_style, werror=args.werror,
wreturn=args.wreturn, wshort_desc=args.wshort_desc,
wcontents_before_sections=args.wcontents_before_sections,
- modulename=args.modulename,
- export_file=args.export_file)
+ modulename=args.modulename)
- kfiles.parse()
+ kfiles.parse(args.files, export_file=args.export_file)
for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
internal=args.internal, symbol=args.symbol,
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 434fc66a9dad..4a6e75dbdbdd 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -123,7 +123,7 @@ class KernelFiles():
self.config.log.error("Cannot find file %s", fname)
self.config.errors += 1
- def __init__(self, files=None, verbose=False, out_style=None,
+ def __init__(self, verbose=False, out_style=None,
werror=False, wreturn=False, wshort_desc=False,
wcontents_before_sections=False,
logger=None, modulename=None, export_file=None):
@@ -180,51 +180,48 @@ class KernelFiles():
self.config.src_tree = os.environ.get("SRCTREE", None)
self.out_style = out_style
- self.export_file = export_file
# Initialize internal variables
self.config.errors = 0
self.results = []
- self.file_list = files
self.files = set()
+ self.export_files = set()
- def parse(self):
+ def parse(self, file_list, export_file=None):
"""
Parse all files
"""
glob = GlobSourceFiles(srctree=self.config.src_tree)
- # Let's use a set here to avoid duplicating files
+ # Prevent parsing the same file twice to speedup parsing and
+ # avoid reporting errors multiple times
- for fname in glob.parse_files(self.file_list, self.file_not_found_cb):
+ for fname in glob.parse_files(file_list, self.file_not_found_cb):
if fname in self.files:
continue
- self.files.add(fname)
-
res = self.parse_file(fname)
+
self.results.append((res.fname, res.entries))
-
- if not self.files:
- sys.exit(1)
+ self.files.add(fname)
# If a list of export files was provided, parse EXPORT_SYMBOL*
- # from the ones not already parsed
+ # from files that weren't fully parsed
- if self.export_file:
- files = self.files
+ if not export_file:
+ return
- glob = GlobSourceFiles(srctree=self.config.src_tree)
+ self.export_files |= self.files
- for fname in glob.parse_files(self.export_file,
- self.file_not_found_cb):
- if fname not in files:
- files.add(fname)
+ glob = GlobSourceFiles(srctree=self.config.src_tree)
- self.process_export_file(fname)
+ for fname in glob.parse_files(export_file, self.file_not_found_cb):
+ if fname not in self.export_files:
+ self.process_export_file(fname)
+ self.export_files.add(fname)
def out_msg(self, fname, name, arg):
"""
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 19/39] scripts/kernel-doc.py: implement support for -no-doc-sections
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (17 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 18/39] scripts/kernel-doc.py: move file lists to the parser function Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 20/39] scripts/kernel-doc.py: fix line number output Mauro Carvalho Chehab
` (20 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
The venerable kernel-doc Perl script has a number of options that
aren't properly documented. Among them, there is -no-doc-sections,
which is used by the Sphinx extension.
Implement support for it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 8 ++++++--
scripts/lib/kdoc/kdoc_files.py | 5 +++--
scripts/lib/kdoc/kdoc_output.py | 7 ++++++-
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index a687a7abb3b9..d700451e9541 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -164,10 +164,13 @@ def main():
sel_mut.add_argument("-s", "-function", "--symbol", action='append',
help=FUNCTION_DESC)
- # This one is valid for all 3 types of filter
+ # Those are valid for all 3 types of filter
parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
help=NOSYMBOL_DESC)
+ parser.add_argument("-D", "-no-doc-sections", "--no-doc-sections",
+ action='store_true', help="Don't outputt DOC sections")
+
parser.add_argument("files", metavar="FILE",
nargs="+", help=FILES_DESC)
@@ -209,7 +212,8 @@ def main():
for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
internal=args.internal, symbol=args.symbol,
- nosymbol=args.nosymbol):
+ nosymbol=args.nosymbol,
+ no_doc_sections=args.no_doc_sections):
msg = t[1]
if msg:
print(msg)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 4a6e75dbdbdd..c215ae3047b8 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -237,7 +237,7 @@ class KernelFiles():
return self.out_style.msg(fname, name, arg)
def msg(self, enable_lineno=False, export=False, internal=False,
- symbol=None, nosymbol=None):
+ symbol=None, nosymbol=None, no_doc_sections=False):
"""
Interacts over the kernel-doc results and output messages,
returning kernel-doc markups on each interaction
@@ -256,7 +256,8 @@ class KernelFiles():
self.out_style.set_config(self.config)
self.out_style.set_filter(export, internal, symbol, nosymbol,
- function_table, enable_lineno)
+ function_table, enable_lineno,
+ no_doc_sections)
for fname, arg_tuple in self.results:
msg = ""
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 91f6e356d03d..8729dc58e13c 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -69,6 +69,7 @@ class OutputFormat:
self.symbol = None
self.function_table = set()
self.config = None
+ self.no_doc_sections = False
self.data = ""
@@ -76,7 +77,7 @@ class OutputFormat:
self.config = config
def set_filter(self, export, internal, symbol, nosymbol, function_table,
- enable_lineno):
+ enable_lineno, no_doc_sections):
"""
Initialize filter variables according with the requested mode.
@@ -86,6 +87,7 @@ class OutputFormat:
"""
self.enable_lineno = enable_lineno
+ self.no_doc_sections = no_doc_sections
if symbol:
self.out_mode = self.OUTPUT_INCLUDE
@@ -116,6 +118,9 @@ class OutputFormat:
def check_doc(self, name):
"""Check if DOC should be output"""
+ if self.no_doc_sections:
+ return False
+
if self.out_mode == self.OUTPUT_ALL:
return True
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 20/39] scripts/kernel-doc.py: fix line number output
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (18 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 19/39] scripts/kernel-doc.py: implement support for -no-doc-sections Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 21/39] scripts/kernel-doc.py: fix handling of doc output check Mauro Carvalho Chehab
` (19 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
With the Pyhton version, the actual output happens after parsing,
from records stored at self.entries.
Ensure that line numbers will be properly stored there and
that they'll produce the desired results at the ReST output.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_output.py | 13 +++++++------
scripts/lib/kdoc/kdoc_parser.py | 21 +++++++++++++++++----
2 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 8729dc58e13c..b9b39bc29463 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -254,7 +254,8 @@ class RestFormat(OutputFormat):
def print_lineno(self, ln):
"""Outputs a line number"""
- if self.enable_lineno and ln:
+ if self.enable_lineno and ln is not None:
+ ln += 1
self.data += f".. LINENO {ln}\n"
def output_highlight(self, args):
@@ -357,7 +358,7 @@ class RestFormat(OutputFormat):
parameterdescs = args.get('parameterdescs', {})
parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
- ln = args.get('ln', 0)
+ ln = args.get('declaration_start_line', 0)
count = 0
for parameter in parameterlist:
@@ -374,11 +375,11 @@ class RestFormat(OutputFormat):
if not func_macro:
signature += ")"
+ self.print_lineno(ln)
if args.get('typedef') or not args.get('functiontype'):
self.data += f".. c:macro:: {args['function']}\n\n"
if args.get('typedef'):
- self.print_lineno(ln)
self.data += " **Typedef**: "
self.lineprefix = ""
self.output_highlight(args.get('purpose', ""))
@@ -433,7 +434,7 @@ class RestFormat(OutputFormat):
name = args.get('enum', '')
parameterlist = args.get('parameterlist', [])
parameterdescs = args.get('parameterdescs', {})
- ln = args.get('ln', 0)
+ ln = args.get('declaration_start_line', 0)
self.data += f"\n\n.. c:enum:: {name}\n\n"
@@ -463,7 +464,7 @@ class RestFormat(OutputFormat):
oldprefix = self.lineprefix
name = args.get('typedef', '')
- ln = args.get('ln', 0)
+ ln = args.get('declaration_start_line', 0)
self.data += f"\n\n.. c:type:: {name}\n\n"
@@ -483,7 +484,7 @@ class RestFormat(OutputFormat):
purpose = args.get('purpose', "")
declaration = args.get('definition', "")
dtype = args.get('type', "struct")
- ln = args.get('ln', 0)
+ ln = args.get('declaration_start_line', 0)
parameterlist = args.get('parameterlist', [])
parameterdescs = args.get('parameterdescs', {})
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 6d6395e32093..633c95164b0c 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -275,7 +275,7 @@ class KernelDoc:
self.entry.brcount = 0
self.entry.in_doc_sect = False
- self.entry.declaration_start_line = ln
+ self.entry.declaration_start_line = ln + 1
def push_parameter(self, ln, decl_type, param, dtype,
org_arg, declaration_name):
@@ -805,8 +805,10 @@ class KernelDoc:
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
parametertypes=self.entry.parametertypes,
+ parameterdesc_start_lines=self.entry.parameterdesc_start_lines,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
purpose=self.entry.declaration_purpose)
def dump_enum(self, ln, proto):
@@ -881,8 +883,10 @@ class KernelDoc:
module=self.config.modulename,
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
+ parameterdesc_start_lines=self.entry.parameterdesc_start_lines,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
purpose=self.entry.declaration_purpose)
def dump_declaration(self, ln, prototype):
@@ -1053,8 +1057,10 @@ class KernelDoc:
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
parametertypes=self.entry.parametertypes,
+ parameterdesc_start_lines=self.entry.parameterdesc_start_lines,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
purpose=self.entry.declaration_purpose,
func_macro=func_macro)
else:
@@ -1066,8 +1072,10 @@ class KernelDoc:
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
parametertypes=self.entry.parametertypes,
+ parameterdesc_start_lines=self.entry.parameterdesc_start_lines,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
purpose=self.entry.declaration_purpose,
func_macro=func_macro)
@@ -1111,8 +1119,10 @@ class KernelDoc:
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
parametertypes=self.entry.parametertypes,
+ parameterdesc_start_lines=self.entry.parameterdesc_start_lines,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
purpose=self.entry.declaration_purpose)
return
@@ -1135,6 +1145,7 @@ class KernelDoc:
module=self.entry.modulename,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
purpose=self.entry.declaration_purpose)
return
@@ -1167,7 +1178,7 @@ class KernelDoc:
return
# start a new entry
- self.reset_state(ln + 1)
+ self.reset_state(ln)
self.entry.in_doc_sect = False
# next line is always the function name
@@ -1280,7 +1291,7 @@ class KernelDoc:
if r.match(line):
self.dump_section()
self.entry.section = self.section_default
- self.entry.new_start_line = line
+ self.entry.new_start_line = ln
self.entry.contents = ""
if doc_sect.search(line):
@@ -1618,7 +1629,9 @@ class KernelDoc:
self.dump_section()
self.output_declaration("doc", None,
sectionlist=self.entry.sectionlist,
- sections=self.entry.sections, module=self.config.modulename)
+ sections=self.entry.sections,
+ section_start_lines=self.entry.section_start_lines,
+ module=self.config.modulename)
self.reset_state(ln)
elif doc_content.search(line):
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 21/39] scripts/kernel-doc.py: fix handling of doc output check
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (19 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 20/39] scripts/kernel-doc.py: fix line number output Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 22/39] scripts/kernel-doc.py: properly handle out_section for ReST Mauro Carvalho Chehab
` (18 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
The filtering logic was seeking for the DOC name to check for
symbols, but such data is stored only inside a section. Add it
to the output_declaration, as it is quicker/easier to check
the declaration name than to check inside each section.
While here, make sure that the output for both ReST and man
after filtering will be similar to what kernel-doc Perl
version does.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_output.py | 29 ++++++++++++-----------------
scripts/lib/kdoc/kdoc_parser.py | 3 ++-
2 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index b9b39bc29463..6a392dad2e9d 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -121,13 +121,13 @@ class OutputFormat:
if self.no_doc_sections:
return False
+ if name in self.nosymbol:
+ return False
+
if self.out_mode == self.OUTPUT_ALL:
return True
if self.out_mode == self.OUTPUT_INCLUDE:
- if name in self.nosymbol:
- return False
-
if name in self.function_table:
return True
@@ -153,15 +153,6 @@ class OutputFormat:
return False
- def check_function(self, fname, name, args):
- return True
-
- def check_enum(self, fname, name, args):
- return True
-
- def check_typedef(self, fname, name, args):
- return True
-
def msg(self, fname, name, args):
self.data = ""
@@ -305,7 +296,7 @@ class RestFormat(OutputFormat):
for line in output.strip("\n").split("\n"):
self.data += self.lineprefix + line + "\n"
- def out_section(self, args, out_reference=False):
+ def out_section(self, args, out_docblock=False):
"""
Outputs a block section.
@@ -324,7 +315,7 @@ class RestFormat(OutputFormat):
continue
if not self.out_mode == self.OUTPUT_INCLUDE:
- if out_reference:
+ if out_docblock:
self.data += f".. _{section}:\n\n"
if not self.symbol:
@@ -338,8 +329,7 @@ class RestFormat(OutputFormat):
def out_doc(self, fname, name, args):
if not self.check_doc(name):
return
-
- self.out_section(args, out_reference=True)
+ self.out_section(args, out_docblock=True)
def out_function(self, fname, name, args):
@@ -582,8 +572,10 @@ class ManFormat(OutputFormat):
for line in contents.strip("\n").split("\n"):
line = Re(r"^\s*").sub("", line)
+ if not line:
+ continue
- if line and line[0] == ".":
+ if line[0] == ".":
self.data += "\\&" + line + "\n"
else:
self.data += line + "\n"
@@ -593,6 +585,9 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
+ if not self.check_doc(name):
+ return
+
self.data += f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX' + "\n"
for section in sectionlist:
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 633c95164b0c..116289622f2c 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -1197,6 +1197,7 @@ class KernelDoc:
else:
self.entry.section = doc_block.group(1)
+ self.entry.identifier = self.entry.section
self.state = self.STATE_DOCBLOCK
return
@@ -1627,7 +1628,7 @@ class KernelDoc:
if doc_end.search(line):
self.dump_section()
- self.output_declaration("doc", None,
+ self.output_declaration("doc", self.entry.identifier,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
section_start_lines=self.entry.section_start_lines,
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 22/39] scripts/kernel-doc.py: properly handle out_section for ReST
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (20 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 21/39] scripts/kernel-doc.py: fix handling of doc output check Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 23/39] scripts/kernel-doc.py: postpone warnings to the output plugin Mauro Carvalho Chehab
` (17 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
There is a difference at the way DOC sections are output with
the include mode. Handle such difference properly.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_output.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 6a392dad2e9d..ca21cd856be4 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -314,12 +314,12 @@ class RestFormat(OutputFormat):
if section in self.nosymbol:
continue
- if not self.out_mode == self.OUTPUT_INCLUDE:
- if out_docblock:
+ if out_docblock:
+ if not self.out_mode == self.OUTPUT_INCLUDE:
self.data += f".. _{section}:\n\n"
-
- if not self.symbol:
self.data += f'{self.lineprefix}**{section}**\n\n'
+ else:
+ self.data += f'{self.lineprefix}**{section}**\n\n'
self.print_lineno(section_start_lines.get(section, 0))
self.output_highlight(sections[section])
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 23/39] scripts/kernel-doc.py: postpone warnings to the output plugin
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (21 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 22/39] scripts/kernel-doc.py: properly handle out_section for ReST Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 24/39] docs: add a .pylintrc file with sys path for docs scripts Mauro Carvalho Chehab
` (16 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
We don't want to have warnings displayed for symbols that
weren't output. So, postpone warnings print to the output
plugin, where symbol output is validated.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_output.py | 24 +++++++++++++++----
scripts/lib/kdoc/kdoc_parser.py | 41 ++++++++++++++++-----------------
2 files changed, 39 insertions(+), 26 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index ca21cd856be4..7aeaec884545 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -115,7 +115,16 @@ class OutputFormat:
return block
- def check_doc(self, name):
+ def out_warnings(self, args):
+ warnings = args.get('warnings', [])
+
+ for warning, log_msg in warnings:
+ if warning:
+ self.config.log.warning(log_msg)
+ else:
+ self.config.log.info(log_msg)
+
+ def check_doc(self, name, args):
"""Check if DOC should be output"""
if self.no_doc_sections:
@@ -125,19 +134,22 @@ class OutputFormat:
return False
if self.out_mode == self.OUTPUT_ALL:
+ self.out_warnings(args)
return True
if self.out_mode == self.OUTPUT_INCLUDE:
if name in self.function_table:
+ self.out_warnings(args)
return True
return False
- def check_declaration(self, dtype, name):
+ def check_declaration(self, dtype, name, args):
if name in self.nosymbol:
return False
if self.out_mode == self.OUTPUT_ALL:
+ self.out_warnings(args)
return True
if self.out_mode in [self.OUTPUT_INCLUDE, self.OUTPUT_EXPORTED]:
@@ -146,9 +158,11 @@ class OutputFormat:
if self.out_mode == self.OUTPUT_INTERNAL:
if dtype != "function":
+ self.out_warnings(args)
return True
if name not in self.function_table:
+ self.out_warnings(args)
return True
return False
@@ -162,7 +176,7 @@ class OutputFormat:
self.out_doc(fname, name, args)
return self.data
- if not self.check_declaration(dtype, name):
+ if not self.check_declaration(dtype, name, args):
return self.data
if dtype == "function":
@@ -327,7 +341,7 @@ class RestFormat(OutputFormat):
self.data += "\n"
def out_doc(self, fname, name, args):
- if not self.check_doc(name):
+ if not self.check_doc(name, args):
return
self.out_section(args, out_docblock=True)
@@ -585,7 +599,7 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- if not self.check_doc(name):
+ if not self.check_doc(name, args):
return
self.data += f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX' + "\n"
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 116289622f2c..a71145d531f2 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -130,23 +130,23 @@ class KernelDoc:
# Place all potential outputs into an array
self.entries = []
- def show_warnings(self, dtype, declaration_name): # pylint: disable=W0613
- """
- Allow filtering out warnings
- """
-
- # TODO: implement it
-
- return True
-
# TODO: rename to emit_message
def emit_warning(self, ln, msg, warning=True):
"""Emit a message"""
+ log_msg = f"{self.fname}:{ln} {msg}"
+
+ if self.entry:
+ # Delegate warning output to output logic, as this way it
+ # will report warnings/info only for symbols that are output
+
+ self.entry.warnings.append((warning, log_msg))
+ return
+
if warning:
- self.config.log.warning("%s:%d %s", self.fname, ln, msg)
+ self.config.log.warning(log_msg)
else:
- self.config.log.info("%s:%d %s", self.fname, ln, msg)
+ self.config.log.info(log_msg)
def dump_section(self, start_new=True):
"""
@@ -220,10 +220,9 @@ class KernelDoc:
# For now, we're keeping the same name of the function just to make
# easier to compare the source code of both scripts
- if "declaration_start_line" not in args:
- args["declaration_start_line"] = self.entry.declaration_start_line
-
+ args["declaration_start_line"] = self.entry.declaration_start_line
args["type"] = dtype
+ args["warnings"] = self.entry.warnings
# TODO: use colletions.OrderedDict
@@ -256,6 +255,8 @@ class KernelDoc:
self.entry.struct_actual = ""
self.entry.prototype = ""
+ self.entry.warnings = []
+
self.entry.parameterlist = []
self.entry.parameterdescs = {}
self.entry.parametertypes = {}
@@ -327,7 +328,7 @@ class KernelDoc:
if param not in self.entry.parameterdescs and not param.startswith("#"):
self.entry.parameterdescs[param] = self.undescribed
- if self.show_warnings(dtype, declaration_name) and "." not in param:
+ if "." not in param:
if decl_type == 'function':
dname = f"{decl_type} parameter"
else:
@@ -867,16 +868,14 @@ class KernelDoc:
self.entry.parameterlist.append(arg)
if arg not in self.entry.parameterdescs:
self.entry.parameterdescs[arg] = self.undescribed
- if self.show_warnings("enum", declaration_name):
- self.emit_warning(ln,
- f"Enum value '{arg}' not described in enum '{declaration_name}'")
+ self.emit_warning(ln,
+ f"Enum value '{arg}' not described in enum '{declaration_name}'")
member_set.add(arg)
for k in self.entry.parameterdescs:
if k not in member_set:
- if self.show_warnings("enum", declaration_name):
- self.emit_warning(ln,
- f"Excess enum value '%{k}' description in '{declaration_name}'")
+ self.emit_warning(ln,
+ f"Excess enum value '%{k}' description in '{declaration_name}'")
self.output_declaration('enum', declaration_name,
enum=declaration_name,
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 24/39] docs: add a .pylintrc file with sys path for docs scripts
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (22 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 23/39] scripts/kernel-doc.py: postpone warnings to the output plugin Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 25/39] docs: sphinx: kerneldoc: verbose kernel-doc command if V=1 Mauro Carvalho Chehab
` (15 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
The docs scripts that are used by Documentation/sphinx are
using scripts/lib/* directories to place classes that will
be used by both extensions and scripts.
When pylint is used, it needs to identify the path where
such scripts are, otherwise it will bail out. Add a simple
RC file placing the location of such files.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
.pylintrc | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 .pylintrc
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 000000000000..30b8ae1659f8
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,2 @@
+[MASTER]
+init-hook='import sys; sys.path += ["scripts/lib/kdoc", "scripts/lib/abi"]'
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 25/39] docs: sphinx: kerneldoc: verbose kernel-doc command if V=1
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (23 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 24/39] docs: add a .pylintrc file with sys path for docs scripts Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 26/39] docs: sphinx: kerneldoc: ignore "\" characters from options Mauro Carvalho Chehab
` (14 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Kees Cook,
linux-kernel
It is useful to know what kernel-doc command was used during
document build time, as it allows one to check the output the same
way as Sphinx extension does.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/sphinx/kerneldoc.py | 34 +++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py
index 39ddae6ae7dd..d206eb2be10a 100644
--- a/Documentation/sphinx/kerneldoc.py
+++ b/Documentation/sphinx/kerneldoc.py
@@ -43,6 +43,29 @@ from sphinx.util import logging
__version__ = '1.0'
+def cmd_str(cmd):
+ """
+ Helper function to output a command line that can be used to produce
+ the same records via command line. Helpful to debug troubles at the
+ script.
+ """
+
+ cmd_line = ""
+
+ for w in cmd:
+ if w == "" or " " in w:
+ esc_cmd = "'" + w + "'"
+ else:
+ esc_cmd = w
+
+ if cmd_line:
+ cmd_line += " " + esc_cmd
+ continue
+ else:
+ cmd_line = esc_cmd
+
+ return cmd_line
+
class KernelDocDirective(Directive):
"""Extract kernel-doc comments from the specified file"""
required_argument = 1
@@ -57,6 +80,7 @@ class KernelDocDirective(Directive):
}
has_content = False
logger = logging.getLogger('kerneldoc')
+ verbose = 0
def run(self):
env = self.state.document.settings.env
@@ -65,6 +89,13 @@ class KernelDocDirective(Directive):
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
export_file_patterns = []
+ verbose = os.environ.get("V")
+ if verbose:
+ try:
+ self.verbose = int(verbose)
+ except ValueError:
+ pass
+
# Tell sphinx of the dependency
env.note_dependency(os.path.abspath(filename))
@@ -104,6 +135,9 @@ class KernelDocDirective(Directive):
cmd += [filename]
+ if self.verbose >= 1:
+ print(cmd_str(cmd))
+
try:
self.logger.verbose("calling kernel-doc '%s'" % (" ".join(cmd)))
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 26/39] docs: sphinx: kerneldoc: ignore "\" characters from options
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (24 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 25/39] docs: sphinx: kerneldoc: verbose kernel-doc command if V=1 Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 27/39] docs: sphinx: kerneldoc: use kernel-doc.py script Mauro Carvalho Chehab
` (13 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Kees Cook,
linux-kernel
Documentation/driver-api/infiniband.rst has a kernel-doc tag
with "\" characters at the end:
.. kernel-doc:: drivers/infiniband/ulp/iser/iscsi_iser.c
:functions: iscsi_iser_pdu_alloc iser_initialize_task_headers \
iscsi_iser_task_init iscsi_iser_mtask_xmit iscsi_iser_task_xmit \
iscsi_iser_cleanup_task iscsi_iser_check_protection \
iscsi_iser_conn_create iscsi_iser_conn_bind \
iscsi_iser_conn_start iscsi_iser_conn_stop \
iscsi_iser_session_destroy iscsi_iser_session_create \
iscsi_iser_set_param iscsi_iser_ep_connect iscsi_iser_ep_poll \
iscsi_iser_ep_disconnect
This is not handled well, as the "\" strings will be just stored inside
Sphinx options.
While the actual problem deserves being fixed, better to relax the
keneldoc.py extension to silently strip "\" from the end of strings,
as otherwise this may cause troubles when preparing arguments to
be executed by kernel-doc.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/sphinx/kerneldoc.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py
index d206eb2be10a..344789ed9ea2 100644
--- a/Documentation/sphinx/kerneldoc.py
+++ b/Documentation/sphinx/kerneldoc.py
@@ -118,6 +118,10 @@ class KernelDocDirective(Directive):
identifiers = self.options.get('identifiers').split()
if identifiers:
for i in identifiers:
+ i = i.rstrip("\\").strip()
+ if not i:
+ continue
+
cmd += ['-function', i]
else:
cmd += ['-no-doc-sections']
@@ -126,9 +130,17 @@ class KernelDocDirective(Directive):
no_identifiers = self.options.get('no-identifiers').split()
if no_identifiers:
for i in no_identifiers:
+ i = i.rstrip("\\").strip()
+ if not i:
+ continue
+
cmd += ['-nosymbol', i]
for pattern in export_file_patterns:
+ pattern = pattern.rstrip("\\").strip()
+ if not pattern:
+ continue
+
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
env.note_dependency(os.path.abspath(f))
cmd += ['-export-file', f]
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 27/39] docs: sphinx: kerneldoc: use kernel-doc.py script
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (25 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 26/39] docs: sphinx: kerneldoc: ignore "\" characters from options Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 28/39] scripts/kernel-doc.py: Set an output format for --none Mauro Carvalho Chehab
` (12 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Switch to the new version when producing documentation.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/Makefile | 2 +-
Documentation/conf.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 63094646df28..c022b97c487e 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -60,7 +60,7 @@ endif #HAVE_LATEXMK
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
-KERNELDOC = $(srctree)/scripts/kernel-doc
+KERNELDOC = $(srctree)/scripts/kernel-doc.py
KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC)
ALLSPHINXOPTS = $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS)
ifneq ($(wildcard $(srctree)/.config),)
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 3dad1f90b098..b126f6760b5f 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -540,7 +540,7 @@ pdf_documents = [
# kernel-doc extension configuration for running Sphinx directly (e.g. by Read
# the Docs). In a normal build, these are supplied from the Makefile via command
# line arguments.
-kerneldoc_bin = '../scripts/kernel-doc'
+kerneldoc_bin = '../scripts/kernel-doc.py'
kerneldoc_srctree = '..'
# ------------------------------------------------------------------------------
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 28/39] scripts/kernel-doc.py: Set an output format for --none
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (26 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 27/39] docs: sphinx: kerneldoc: use kernel-doc.py script Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 29/39] scripts/kernel-doc.py: adjust some coding style issues Mauro Carvalho Chehab
` (11 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Now that warnings output is deferred to the output plugin, we
need to have an output style for none as well.
So, use the OutputFormat base class on such cases.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_files.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index c215ae3047b8..957aaeaed7e6 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -19,6 +19,7 @@ from datetime import datetime
from dateutil import tz
from kdoc_parser import KernelDoc
+from kdoc_output import OutputFormat
class GlobSourceFiles:
@@ -137,6 +138,9 @@ class KernelFiles():
if not modulename:
modulename = "Kernel API"
+ if out_style is None:
+ out_style = OutputFormat()
+
dt = datetime.now()
if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
# use UTC TZ
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 29/39] scripts/kernel-doc.py: adjust some coding style issues
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (27 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 28/39] scripts/kernel-doc.py: Set an output format for --none Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 30/39] scripts/lib/kdoc/kdoc_parser.py: fix Python compat with < v3.13 Mauro Carvalho Chehab
` (10 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Make pylint happier by adding some missing documentation and
addressing a couple of pylint warnings.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 2 ++
scripts/lib/kdoc/kdoc_files.py | 4 +--
scripts/lib/kdoc/kdoc_output.py | 51 ++++++++++++++++++++++++++-------
3 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index d700451e9541..daae2b4f3307 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -90,6 +90,8 @@ neither here nor at the original Perl script.
class MsgFormatter(logging.Formatter):
+ """Helper class to format warnings on a similar way to kernel-doc.pl"""
+
def format(self, record):
record.levelname = record.levelname.capitalize()
return logging.Formatter.format(self, record)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 957aaeaed7e6..e1ed2f6dae94 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -3,8 +3,6 @@
# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
# SPDX-License-Identifier: GPL-2.0
-# TODO: implement warning filtering
-
"""
Parse lernel-doc tags on multiple kernel source files.
"""
@@ -127,7 +125,7 @@ class KernelFiles():
def __init__(self, verbose=False, out_style=None,
werror=False, wreturn=False, wshort_desc=False,
wcontents_before_sections=False,
- logger=None, modulename=None, export_file=None):
+ logger=None, modulename=None):
"""
Initialize startup variables and parse all files
"""
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 7aeaec884545..97ec671e0b6e 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -1,10 +1,8 @@
#!/usr/bin/env python3
-# pylint: disable=C0301,R0911,R0912,R0913,R0914,R0915,R0917
+# pylint: disable=C0301,R0902,R0911,R0912,R0913,R0914,R0915,R0917
# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
# SPDX-License-Identifier: GPL-2.0
-# TODO: implement warning filtering
-
"""
Implement output filters to print kernel-doc documentation.
@@ -51,6 +49,11 @@ type_member_func = type_member + Re(r"\(\)", cache=False)
class OutputFormat:
+ """
+ Base class for OutputFormat. If used as-is, it means that only
+ warnings will be displayed.
+ """
+
# output mode.
OUTPUT_ALL = 0 # output all symbols and doc sections
OUTPUT_INCLUDE = 1 # output only specified symbols
@@ -74,6 +77,10 @@ class OutputFormat:
self.data = ""
def set_config(self, config):
+ """
+ Setup global config variables used by both parser and output.
+ """
+
self.config = config
def set_filter(self, export, internal, symbol, nosymbol, function_table,
@@ -116,6 +123,10 @@ class OutputFormat:
return block
def out_warnings(self, args):
+ """
+ Output warnings for identifiers that will be displayed.
+ """
+
warnings = args.get('warnings', [])
for warning, log_msg in warnings:
@@ -145,6 +156,11 @@ class OutputFormat:
return False
def check_declaration(self, dtype, name, args):
+ """
+ Checks if a declaration should be output or not based on the
+ filtering criteria.
+ """
+
if name in self.nosymbol:
return False
@@ -168,6 +184,10 @@ class OutputFormat:
return False
def msg(self, fname, name, args):
+ """
+ Handles a single entry from kernel-doc parser
+ """
+
self.data = ""
dtype = args.get('type', "")
@@ -202,24 +222,24 @@ class OutputFormat:
return None
# Virtual methods to be overridden by inherited classes
+ # At the base class, those do nothing.
def out_doc(self, fname, name, args):
- pass
+ """Outputs a DOC block"""
def out_function(self, fname, name, args):
- pass
+ """Outputs a function"""
def out_enum(self, fname, name, args):
- pass
+ """Outputs an enum"""
def out_typedef(self, fname, name, args):
- pass
+ """Outputs a typedef"""
def out_struct(self, fname, name, args):
- pass
-
+ """Outputs a struct"""
class RestFormat(OutputFormat):
- # """Consts and functions used by ReST output"""
+ """Consts and functions used by ReST output"""
highlights = [
(type_constant, r"``\1``"),
@@ -264,6 +284,11 @@ class RestFormat(OutputFormat):
self.data += f".. LINENO {ln}\n"
def output_highlight(self, args):
+ """
+ Outputs a C symbol that may require being converted to ReST using
+ the self.highlights variable
+ """
+
input_text = args
output = ""
in_literal = False
@@ -578,6 +603,10 @@ class ManFormat(OutputFormat):
self.man_date = dt.strftime("%B %Y")
def output_highlight(self, block):
+ """
+ Outputs a C symbol that may require being highlighted with
+ self.highlights variable using troff syntax
+ """
contents = self.highlight_block(block)
@@ -600,7 +629,7 @@ class ManFormat(OutputFormat):
sections = args.get('sections', {})
if not self.check_doc(name, args):
- return
+ return
self.data += f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX' + "\n"
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 30/39] scripts/lib/kdoc/kdoc_parser.py: fix Python compat with < v3.13
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (28 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 29/39] scripts/kernel-doc.py: adjust some coding style issues Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 31/39] scripts/kernel-doc.py: move modulename to man class Mauro Carvalho Chehab
` (9 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
- str.replace count was introduced only in Python 3.13;
- before Python 3.13, f-string dict arguments can't use the same
delimiter of the main string.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_output.py | 8 ++++----
scripts/lib/kdoc/kdoc_parser.py | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 97ec671e0b6e..df3c15bb1c10 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -645,16 +645,16 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- self.data += f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX' + "\n"
+ self.data += f'.TH "{args["function"]}" 9 "{args["function"]}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX' + "\n"
self.data += ".SH NAME\n"
self.data += f"{args['function']} \\- {args['purpose']}\n"
self.data += ".SH SYNOPSIS\n"
if args.get('functiontype', ''):
- self.data += f'.B "{args['functiontype']}" {args['function']}' + "\n"
+ self.data += f'.B "{args["functiontype"]}" {args["function"]}' + "\n"
else:
- self.data += f'.B "{args['function']}' + "\n"
+ self.data += f'.B "{args["function"]}' + "\n"
count = 0
parenth = "("
@@ -695,7 +695,7 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- self.data += f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX' + "\n"
+ self.data += f'.TH "{args["module"]}" 9 "enum {args["enum"]}" "{self.man_date}" "API Manual" LINUX' + "\n"
self.data += ".SH NAME\n"
self.data += f"enum {args['enum']} \\- {args['purpose']}\n"
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index a71145d531f2..51ac2d69a587 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -1455,9 +1455,9 @@ class KernelDoc:
r = Re(r'long\s+(sys_.*?),')
if r.search(proto):
- proto = proto.replace(',', '(', count=1)
+ proto = Re(',').sub('(', proto, count=1)
elif is_void:
- proto = proto.replace(')', '(void)', count=1)
+ proto = Re(r'\)').sub('(void)', proto, count=1)
# Now delete all of the odd-numbered commas in the proto
# so that argument types & names don't have a comma between them
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 31/39] scripts/kernel-doc.py: move modulename to man class
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (29 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 30/39] scripts/lib/kdoc/kdoc_parser.py: fix Python compat with < v3.13 Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 32/39] scripts/kernel-doc.py: properly handle KBUILD_BUILD_TIMESTAMP Mauro Carvalho Chehab
` (8 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Only man output requires a modulename. Move its definition
to the man class.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 6 +++---
scripts/lib/kdoc/kdoc_files.py | 6 +-----
scripts/lib/kdoc/kdoc_output.py | 12 ++++++------
scripts/lib/kdoc/kdoc_parser.py | 9 +--------
4 files changed, 11 insertions(+), 22 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index daae2b4f3307..064106c18d8b 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -111,6 +111,7 @@ def main():
help="Enable debug messages")
parser.add_argument("-M", "-modulename", "--modulename",
+ default="Kernel API",
help="Allow setting a module name at the output.")
parser.add_argument("-l", "-enable-lineno", "--enable_lineno",
@@ -198,7 +199,7 @@ def main():
logger.addHandler(handler)
if args.man:
- out_style = ManFormat()
+ out_style = ManFormat(modulename=args.modulename)
elif args.none:
out_style = None
else:
@@ -207,8 +208,7 @@ def main():
kfiles = KernelFiles(verbose=args.verbose,
out_style=out_style, werror=args.werror,
wreturn=args.wreturn, wshort_desc=args.wshort_desc,
- wcontents_before_sections=args.wcontents_before_sections,
- modulename=args.modulename)
+ wcontents_before_sections=args.wcontents_before_sections)
kfiles.parse(args.files, export_file=args.export_file)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index e1ed2f6dae94..a2417cafb1c8 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -125,7 +125,7 @@ class KernelFiles():
def __init__(self, verbose=False, out_style=None,
werror=False, wreturn=False, wshort_desc=False,
wcontents_before_sections=False,
- logger=None, modulename=None):
+ logger=None):
"""
Initialize startup variables and parse all files
"""
@@ -133,9 +133,6 @@ class KernelFiles():
if not verbose:
verbose = bool(os.environ.get("KBUILD_VERBOSE", 0))
- if not modulename:
- modulename = "Kernel API"
-
if out_style is None:
out_style = OutputFormat()
@@ -167,7 +164,6 @@ class KernelFiles():
self.config.wreturn = wreturn
self.config.wshort_desc = wshort_desc
self.config.wcontents_before_sections = wcontents_before_sections
- self.config.modulename = modulename
self.config.function_table = set()
self.config.source_map = {}
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index df3c15bb1c10..13a74a687f89 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -584,7 +584,7 @@ class ManFormat(OutputFormat):
)
blankline = ""
- def __init__(self):
+ def __init__(self, modulename):
"""
Creates class variables.
@@ -593,6 +593,7 @@ class ManFormat(OutputFormat):
"""
super().__init__()
+ self.modulename = modulename
dt = datetime.now()
if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
@@ -624,14 +625,13 @@ class ManFormat(OutputFormat):
self.data += line + "\n"
def out_doc(self, fname, name, args):
- module = args.get('module')
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
if not self.check_doc(name, args):
return
- self.data += f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX' + "\n"
+ self.data += f'.TH "{self.modulename}" 9 "{self.modulename}" "{self.man_date}" "API Manual" LINUX' + "\n"
for section in sectionlist:
self.data += f'.SH "{section}"' + "\n"
@@ -695,7 +695,7 @@ class ManFormat(OutputFormat):
sectionlist = args.get('sectionlist', [])
sections = args.get('sections', {})
- self.data += f'.TH "{args["module"]}" 9 "enum {args["enum"]}" "{self.man_date}" "API Manual" LINUX' + "\n"
+ self.data += f'.TH "{self.modulename}" 9 "enum {args["enum"]}" "{self.man_date}" "API Manual" LINUX' + "\n"
self.data += ".SH NAME\n"
self.data += f"enum {args['enum']} \\- {args['purpose']}\n"
@@ -725,7 +725,7 @@ class ManFormat(OutputFormat):
self.output_highlight(sections[section])
def out_typedef(self, fname, name, args):
- module = args.get('module')
+ module = self.modulename
typedef = args.get('typedef')
purpose = args.get('purpose')
sectionlist = args.get('sectionlist', [])
@@ -741,7 +741,7 @@ class ManFormat(OutputFormat):
self.output_highlight(sections.get(section))
def out_struct(self, fname, name, args):
- module = args.get('module')
+ module = self.modulename
struct_type = args.get('type')
struct_name = args.get('struct')
purpose = args.get('purpose')
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 51ac2d69a587..0c0fa10b942b 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -801,7 +801,6 @@ class KernelDoc:
self.output_declaration(decl_type, declaration_name,
struct=declaration_name,
- module=self.entry.modulename,
definition=declaration,
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
@@ -879,7 +878,6 @@ class KernelDoc:
self.output_declaration('enum', declaration_name,
enum=declaration_name,
- module=self.config.modulename,
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
parameterdesc_start_lines=self.entry.parameterdesc_start_lines,
@@ -1051,7 +1049,6 @@ class KernelDoc:
self.output_declaration(decl_type, declaration_name,
function=declaration_name,
typedef=True,
- module=self.config.modulename,
functiontype=return_type,
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
@@ -1066,7 +1063,6 @@ class KernelDoc:
self.output_declaration(decl_type, declaration_name,
function=declaration_name,
typedef=False,
- module=self.config.modulename,
functiontype=return_type,
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
@@ -1113,7 +1109,6 @@ class KernelDoc:
self.output_declaration(decl_type, declaration_name,
function=declaration_name,
typedef=True,
- module=self.entry.modulename,
functiontype=return_type,
parameterlist=self.entry.parameterlist,
parameterdescs=self.entry.parameterdescs,
@@ -1141,7 +1136,6 @@ class KernelDoc:
self.output_declaration('typedef', declaration_name,
typedef=declaration_name,
- module=self.entry.modulename,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
section_start_lines=self.entry.section_start_lines,
@@ -1630,8 +1624,7 @@ class KernelDoc:
self.output_declaration("doc", self.entry.identifier,
sectionlist=self.entry.sectionlist,
sections=self.entry.sections,
- section_start_lines=self.entry.section_start_lines,
- module=self.config.modulename)
+ section_start_lines=self.entry.section_start_lines)
self.reset_state(ln)
elif doc_content.search(line):
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 32/39] scripts/kernel-doc.py: properly handle KBUILD_BUILD_TIMESTAMP
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (30 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 31/39] scripts/kernel-doc.py: move modulename to man class Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 33/39] scripts/lib/kdoc/kdoc_parser.py: remove a python 3.9 dependency Mauro Carvalho Chehab
` (7 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
The logic that handles KBUILD_BUILD_TIMESTAMP is wrong, and adds
a dependency of a third party module (dateutil).
Fix it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_files.py | 9 ---------
scripts/lib/kdoc/kdoc_output.py | 28 +++++++++++++++++++++-------
2 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index a2417cafb1c8..19fe9c6f5352 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -12,9 +12,6 @@ import logging
import os
import re
import sys
-from datetime import datetime
-
-from dateutil import tz
from kdoc_parser import KernelDoc
from kdoc_output import OutputFormat
@@ -136,12 +133,6 @@ class KernelFiles():
if out_style is None:
out_style = OutputFormat()
- dt = datetime.now()
- if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
- # use UTC TZ
- to_zone = tz.gettz('UTC')
- dt = dt.astimezone(to_zone)
-
if not werror:
kcflags = os.environ.get("KCFLAGS", None)
if kcflags:
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 13a74a687f89..166fcabbb4cf 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -18,8 +18,6 @@ import os
import re
from datetime import datetime
-from dateutil import tz
-
from kdoc_parser import KernelDoc, type_param
from kdoc_re import Re
@@ -584,6 +582,15 @@ class ManFormat(OutputFormat):
)
blankline = ""
+ date_formats = [
+ "%a %b %d %H:%M:%S %Z %Y",
+ "%a %b %d %H:%M:%S %Y",
+ "%Y-%m-%d",
+ "%b %d %Y",
+ "%B %d %Y",
+ "%m %d %Y",
+ ]
+
def __init__(self, modulename):
"""
Creates class variables.
@@ -595,11 +602,18 @@ class ManFormat(OutputFormat):
super().__init__()
self.modulename = modulename
- dt = datetime.now()
- if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
- # use UTC TZ
- to_zone = tz.gettz('UTC')
- dt = dt.astimezone(to_zone)
+ dt = None
+ tstamp = os.environ.get("KBUILD_BUILD_TIMESTAMP")
+ if tstamp:
+ for fmt in self.date_formats:
+ try:
+ dt = datetime.strptime(tstamp, fmt)
+ break
+ except ValueError:
+ pass
+
+ if not dt:
+ dt = datetime.now()
self.man_date = dt.strftime("%B %Y")
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 33/39] scripts/lib/kdoc/kdoc_parser.py: remove a python 3.9 dependency
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (31 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 32/39] scripts/kernel-doc.py: properly handle KBUILD_BUILD_TIMESTAMP Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 34/39] scripts/kernel-doc.py: Properly handle Werror and exit codes Mauro Carvalho Chehab
` (6 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
str.removesuffix() was added on Python 3.9, but rstrip()
actually does the same thing, as we just want to remove a single
character. It is also shorter.
So, use it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_parser.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 0c0fa10b942b..feac699a3893 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -1652,7 +1652,7 @@ class KernelDoc:
# Group continuation lines on prototypes
if self.state == self.STATE_PROTO:
if line.endswith("\\"):
- prev += line.removesuffix("\\")
+ prev += line.rstrip("\\")
cont = True
if not prev_ln:
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 34/39] scripts/kernel-doc.py: Properly handle Werror and exit codes
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (32 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 33/39] scripts/lib/kdoc/kdoc_parser.py: remove a python 3.9 dependency Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 35/39] scripts/kernel-doc.py: some coding style cleanups Mauro Carvalho Chehab
` (5 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
The original kernel-doc script has a logic to return warnings
as errors, and to report the number of warnings found, if in
verbose mode.
Implement it to be fully compatible with the original script.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 18 ++++++++++++++++--
scripts/lib/kdoc/kdoc_files.py | 11 ++++++++++-
scripts/lib/kdoc/kdoc_output.py | 8 +++-----
scripts/lib/kdoc/kdoc_parser.py | 15 ++++++---------
4 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 064106c18d8b..7683fb4ffc59 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -3,8 +3,6 @@
# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
# SPDX-License-Identifier: GPL-2.0
-# TODO: implement warning filtering
-
"""
kernel_doc
==========
@@ -220,6 +218,22 @@ def main():
if msg:
print(msg)
+ error_count = kfiles.errors
+ if not error_count:
+ sys.exit(0)
+
+ if args.werror:
+ print(f"{error_count} warnings as errors")
+ sys.exit(error_count)
+
+ if args.verbose:
+ print(f"{error_count} errors")
+
+ if args.none:
+ sys.exit(0)
+
+ sys.exit(error_count)
+
# Call main method
if __name__ == "__main__":
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 19fe9c6f5352..e130e5e32806 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -108,7 +108,7 @@ class KernelFiles():
KernelDoc.process_export(self.config.function_table, line)
except IOError:
- print(f"Error: Cannot open fname {fname}", fname=sys.stderr)
+ self.config.log.error("Error: Cannot open fname %s", fname)
self.config.errors += 1
def file_not_found_cb(self, fname):
@@ -261,3 +261,12 @@ class KernelFiles():
fname, ln, dtype)
if msg:
yield fname, msg
+
+ @property
+ def errors(self):
+ """
+ Return a count of the number of warnings found, including
+ the ones displayed while interacting over self.msg.
+ """
+
+ return self.config.errors
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 166fcabbb4cf..d0cb7f511f87 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -127,11 +127,9 @@ class OutputFormat:
warnings = args.get('warnings', [])
- for warning, log_msg in warnings:
- if warning:
- self.config.log.warning(log_msg)
- else:
- self.config.log.info(log_msg)
+ for log_msg in warnings:
+ self.config.log.warning(log_msg)
+ self.config.errors += 1
def check_doc(self, name, args):
"""Check if DOC should be output"""
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index feac699a3893..6cebc32e18f2 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -136,17 +136,18 @@ class KernelDoc:
log_msg = f"{self.fname}:{ln} {msg}"
+ if not warning:
+ self.config.log.info(log_msg)
+ return
+
if self.entry:
# Delegate warning output to output logic, as this way it
# will report warnings/info only for symbols that are output
- self.entry.warnings.append((warning, log_msg))
+ self.entry.warnings.append(log_msg)
return
- if warning:
- self.config.log.warning(log_msg)
- else:
- self.config.log.info(log_msg)
+ self.config.log.warning(log_msg)
def dump_section(self, start_new=True):
"""
@@ -568,7 +569,6 @@ class KernelDoc:
if not members:
self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
- self.config.errors += 1
return
if self.entry.identifier != declaration_name:
@@ -841,7 +841,6 @@ class KernelDoc:
if not members:
self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
- self.config.errors += 1
return
if self.entry.identifier != declaration_name:
@@ -1143,7 +1142,6 @@ class KernelDoc:
return
self.emit_warning(ln, "error: Cannot parse typedef!")
- self.config.errors += 1
@staticmethod
def process_export(function_table, line):
@@ -1692,4 +1690,3 @@ class KernelDoc:
self.process_docblock(ln, line)
except OSError:
self.config.log.error(f"Error: Cannot open file {self.fname}")
- self.config.errors += 1
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 35/39] scripts/kernel-doc.py: some coding style cleanups
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (33 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 34/39] scripts/kernel-doc.py: Properly handle Werror and exit codes Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 36/39] scripts/kernel-doc: switch to use kernel-doc.py Mauro Carvalho Chehab
` (4 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Remove some warnings generated by pylint. Among them, cleanup
TODO messages, removing the ones that were already handled,
as now all TODOs that are required to be fully compatible with
kernel-doc were already addressed.
So, the existing TODOs are pointing possible future cleanups and
improvements.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 10 +++++-----
scripts/lib/kdoc/kdoc_files.py | 1 -
scripts/lib/kdoc/kdoc_output.py | 1 +
scripts/lib/kdoc/kdoc_parser.py | 30 +++++++-----------------------
scripts/lib/kdoc/kdoc_re.py | 3 ++-
5 files changed, 15 insertions(+), 30 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 7683fb4ffc59..5e1e1839438c 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# pylint: disable=C0103,
+# pylint: disable=C0103,R0915
# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
# SPDX-License-Identifier: GPL-2.0
@@ -167,7 +167,7 @@ def main():
# Those are valid for all 3 types of filter
parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
- help=NOSYMBOL_DESC)
+ help=NOSYMBOL_DESC)
parser.add_argument("-D", "-no-doc-sections", "--no-doc-sections",
action='store_true', help="Don't outputt DOC sections")
@@ -211,9 +211,9 @@ def main():
kfiles.parse(args.files, export_file=args.export_file)
for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
- internal=args.internal, symbol=args.symbol,
- nosymbol=args.nosymbol,
- no_doc_sections=args.no_doc_sections):
+ internal=args.internal, symbol=args.symbol,
+ nosymbol=args.nosymbol,
+ no_doc_sections=args.no_doc_sections):
msg = t[1]
if msg:
print(msg)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index e130e5e32806..fc14bd6f9863 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -11,7 +11,6 @@ import argparse
import logging
import os
import re
-import sys
from kdoc_parser import KernelDoc
from kdoc_output import OutputFormat
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index d0cb7f511f87..487068753b53 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -234,6 +234,7 @@ class OutputFormat:
def out_struct(self, fname, name, args):
"""Outputs a struct"""
+
class RestFormat(OutputFormat):
"""Consts and functions used by ReST output"""
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index 6cebc32e18f2..cf4bf7cedcbc 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -130,7 +130,7 @@ class KernelDoc:
# Place all potential outputs into an array
self.entries = []
- # TODO: rename to emit_message
+ # TODO: rename to emit_message after removal of kernel-doc.pl
def emit_warning(self, ln, msg, warning=True):
"""Emit a message"""
@@ -157,19 +157,6 @@ class KernelDoc:
name = self.entry.section
contents = self.entry.contents
- # TODO: we can prevent dumping empty sections here with:
- #
- # if self.entry.contents.strip("\n"):
- # if start_new:
- # self.entry.section = self.section_default
- # self.entry.contents = ""
- #
- # return
- #
- # But, as we want to be producing the same output of the
- # venerable kernel-doc Perl tool, let's just output everything,
- # at least for now
-
if type_param.match(name):
name = type_param.group(1)
@@ -205,7 +192,7 @@ class KernelDoc:
self.entry.section = self.section_default
self.entry.contents = ""
- # TODO: rename it to store_declaration
+ # TODO: rename it to store_declaration after removal of kernel-doc.pl
def output_declaration(self, dtype, name, **args):
"""
Stores the entry into an entry array.
@@ -225,13 +212,13 @@ class KernelDoc:
args["type"] = dtype
args["warnings"] = self.entry.warnings
- # TODO: use colletions.OrderedDict
+ # TODO: use colletions.OrderedDict to remove sectionlist
sections = args.get('sections', {})
sectionlist = args.get('sectionlist', [])
# Drop empty sections
- # TODO: improve it to emit warnings
+ # TODO: improve empty sections logic to emit warnings
for section in ["Description", "Return"]:
if section in sectionlist:
if not sections[section].rstrip():
@@ -635,7 +622,9 @@ class KernelDoc:
# Replace macros
#
- # TODO: it is better to also move those to the NestedMatch logic,
+ # TODO: use NestedMatch for FOO($1, $2, ...) matches
+ #
+ # it is better to also move those to the NestedMatch logic,
# to ensure that parenthesis will be properly matched.
(Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
@@ -902,7 +891,6 @@ class KernelDoc:
self.dump_struct(ln, prototype)
return
- # TODO: handle other types
self.output_declaration(self.entry.decl_type, prototype,
entry=self.entry)
@@ -1670,10 +1658,6 @@ class KernelDoc:
self.st_inline_name[self.inline_doc_state],
line)
- # TODO: not all states allow EXPORT_SYMBOL*, so this
- # can be optimized later on to speedup parsing
- self.process_export(self.config.function_table, line)
-
# Hand this line to the appropriate state handler
if self.state == self.STATE_NORMAL:
self.process_normal(ln, line)
diff --git a/scripts/lib/kdoc/kdoc_re.py b/scripts/lib/kdoc/kdoc_re.py
index 45ddba8090e5..de362ec38db7 100755
--- a/scripts/lib/kdoc/kdoc_re.py
+++ b/scripts/lib/kdoc/kdoc_re.py
@@ -131,7 +131,8 @@ class NestedMatch:
will ignore the search string.
"""
- # TODO:
+ # TODO: make NestedMatch handle multiple match groups
+ #
# Right now, regular expressions to match it are defined only up to
# the start delimiter, e.g.:
#
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 36/39] scripts/kernel-doc: switch to use kernel-doc.py
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (34 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 35/39] scripts/kernel-doc.py: some coding style cleanups Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 37/39] scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname Mauro Carvalho Chehab
` (3 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Now that all features are in place, change the kernel-doc alias
to point to kernel-doc.py.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index f175155c1e66..3b6ef807791a 120000
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1 +1 @@
-kernel-doc.pl
\ No newline at end of file
+kernel-doc.py
\ No newline at end of file
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 37/39] scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (35 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 36/39] scripts/kernel-doc: switch to use kernel-doc.py Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 38/39] scripts/kernel_doc.py: better handle exported symbols Mauro Carvalho Chehab
` (2 subsequent siblings)
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
For kerneldoc Sphinx extension, it is useful to display
parsed results only from a single file. Change the logic at
KernelFiles.msg() to allow such usage.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/lib/kdoc/kdoc_files.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index fc14bd6f9863..8935a8603b44 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -94,7 +94,7 @@ class KernelFiles():
doc = KernelDoc(self.config, fname)
doc.run()
- return doc
+ return doc.entries
def process_export_file(self, fname):
"""
@@ -172,7 +172,7 @@ class KernelFiles():
# Initialize internal variables
self.config.errors = 0
- self.results = []
+ self.results = {}
self.files = set()
self.export_files = set()
@@ -188,13 +188,9 @@ class KernelFiles():
# avoid reporting errors multiple times
for fname in glob.parse_files(file_list, self.file_not_found_cb):
- if fname in self.files:
- continue
-
- res = self.parse_file(fname)
-
- self.results.append((res.fname, res.entries))
- self.files.add(fname)
+ if fname not in self.files:
+ self.results[fname] = self.parse_file(fname)
+ self.files.add(fname)
# If a list of export files was provided, parse EXPORT_SYMBOL*
# from files that weren't fully parsed
@@ -225,7 +221,8 @@ class KernelFiles():
return self.out_style.msg(fname, name, arg)
def msg(self, enable_lineno=False, export=False, internal=False,
- symbol=None, nosymbol=None, no_doc_sections=False):
+ symbol=None, nosymbol=None, no_doc_sections=False,
+ filenames=None):
"""
Interacts over the kernel-doc results and output messages,
returning kernel-doc markups on each interaction
@@ -247,9 +244,12 @@ class KernelFiles():
function_table, enable_lineno,
no_doc_sections)
- for fname, arg_tuple in self.results:
+ if not filenames:
+ filenames = sorted(self.results.keys())
+
+ for fname in filenames:
msg = ""
- for name, arg in arg_tuple:
+ for name, arg in self.results[fname]:
msg += self.out_msg(fname, name, arg)
if msg is None:
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 38/39] scripts/kernel_doc.py: better handle exported symbols
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (36 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 37/39] scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 39/39] docs: sphinx: kerneldoc: Use python class if available Mauro Carvalho Chehab
2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Change the logic which detects internal/external symbols in a way
that we can re-use it when calling via Sphinx extension.
While here, remove an unused self.config var and let it clearer
that self.config variables are read-only. This helps to allow
handling multiple times in parallel if ever needed.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
scripts/kernel-doc.py | 2 +-
scripts/lib/kdoc/kdoc_files.py | 142 +++++++++++++++++---------------
scripts/lib/kdoc/kdoc_output.py | 9 +-
scripts/lib/kdoc/kdoc_parser.py | 52 ++++++++++--
4 files changed, 125 insertions(+), 80 deletions(-)
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 5e1e1839438c..eb308c938717 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -212,7 +212,7 @@ def main():
for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
internal=args.internal, symbol=args.symbol,
- nosymbol=args.nosymbol,
+ nosymbol=args.nosymbol, export_file=args.export_file,
no_doc_sections=args.no_doc_sections):
msg = t[1]
if msg:
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py
index 8935a8603b44..6da93febdb01 100755
--- a/scripts/lib/kdoc/kdoc_files.py
+++ b/scripts/lib/kdoc/kdoc_files.py
@@ -67,6 +67,9 @@ class GlobSourceFiles:
handling directories if any
"""
+ if not file_list:
+ return
+
for fname in file_list:
if self.srctree:
f = os.path.join(self.srctree, fname)
@@ -83,40 +86,70 @@ class GlobSourceFiles:
class KernelFiles():
"""
- Parse lernel-doc tags on multiple kernel source files.
+ Parse kernel-doc tags on multiple kernel source files.
+
+ There are two type of parsers defined here:
+ - self.parse_file(): parses both kernel-doc markups and
+ EXPORT_SYMBOL* macros;
+ - self.process_export_file(): parses only EXPORT_SYMBOL* macros.
"""
+ def warning(self, msg):
+ """Ancillary routine to output a warning and increment error count"""
+
+ self.config.log.warning(msg)
+ self.errors += 1
+
+ def error(self, msg):
+ """Ancillary routine to output an error and increment error count"""
+
+ self.config.log.error(msg)
+ self.errors += 1
+
def parse_file(self, fname):
"""
Parse a single Kernel source.
"""
+ # Prevent parsing the same file twice if results are cached
+ if fname in self.files:
+ return
+
doc = KernelDoc(self.config, fname)
- doc.run()
+ export_table, entries = doc.parse_kdoc()
- return doc.entries
+ self.export_table[fname] = export_table
+
+ self.files.add(fname)
+ self.export_files.add(fname) # parse_kdoc() already check exports
+
+ self.results[fname] = entries
def process_export_file(self, fname):
"""
Parses EXPORT_SYMBOL* macros from a single Kernel source file.
"""
- try:
- with open(fname, "r", encoding="utf8",
- errors="backslashreplace") as fp:
- for line in fp:
- KernelDoc.process_export(self.config.function_table, line)
-
- except IOError:
- self.config.log.error("Error: Cannot open fname %s", fname)
- self.config.errors += 1
+
+ # Prevent parsing the same file twice if results are cached
+ if fname in self.export_files:
+ return
+
+ doc = KernelDoc(self.config, fname)
+ export_table = doc.parse_export()
+
+ if not export_table:
+ self.error(f"Error: Cannot check EXPORT_SYMBOL* on {fname}")
+ export_table = set()
+
+ self.export_table[fname] = export_table
+ self.export_files.add(fname)
def file_not_found_cb(self, fname):
"""
Callback to warn if a file was not found.
"""
- self.config.log.error("Cannot find file %s", fname)
- self.config.errors += 1
+ self.error(f"Cannot find file {fname}")
def __init__(self, verbose=False, out_style=None,
werror=False, wreturn=False, wshort_desc=False,
@@ -146,7 +179,9 @@ class KernelFiles():
if kdoc_werror:
werror = kdoc_werror
- # Set global config data used on all files
+ # Some variables are global to the parser logic as a whole as they are
+ # used to send control configuration to KernelDoc class. As such,
+ # those variables are read-only inside the KernelDoc.
self.config = argparse.Namespace
self.config.verbose = verbose
@@ -155,27 +190,25 @@ class KernelFiles():
self.config.wshort_desc = wshort_desc
self.config.wcontents_before_sections = wcontents_before_sections
- self.config.function_table = set()
- self.config.source_map = {}
-
if not logger:
self.config.log = logging.getLogger("kernel-doc")
else:
self.config.log = logger
- self.config.kernel_version = os.environ.get("KERNELVERSION",
- "unknown kernel version'")
+ self.config.warning = self.warning
+
self.config.src_tree = os.environ.get("SRCTREE", None)
+ # Initialize variables that are internal to KernelFiles
+
self.out_style = out_style
- # Initialize internal variables
-
- self.config.errors = 0
+ self.errors = 0
self.results = {}
self.files = set()
self.export_files = set()
+ self.export_table = {}
def parse(self, file_list, export_file=None):
"""
@@ -184,28 +217,11 @@ class KernelFiles():
glob = GlobSourceFiles(srctree=self.config.src_tree)
- # Prevent parsing the same file twice to speedup parsing and
- # avoid reporting errors multiple times
-
for fname in glob.parse_files(file_list, self.file_not_found_cb):
- if fname not in self.files:
- self.results[fname] = self.parse_file(fname)
- self.files.add(fname)
-
- # If a list of export files was provided, parse EXPORT_SYMBOL*
- # from files that weren't fully parsed
-
- if not export_file:
- return
-
- self.export_files |= self.files
-
- glob = GlobSourceFiles(srctree=self.config.src_tree)
+ self.parse_file(fname)
for fname in glob.parse_files(export_file, self.file_not_found_cb):
- if fname not in self.export_files:
- self.process_export_file(fname)
- self.export_files.add(fname)
+ self.process_export_file(fname)
def out_msg(self, fname, name, arg):
"""
@@ -222,32 +238,35 @@ class KernelFiles():
def msg(self, enable_lineno=False, export=False, internal=False,
symbol=None, nosymbol=None, no_doc_sections=False,
- filenames=None):
+ filenames=None, export_file=None):
"""
Interacts over the kernel-doc results and output messages,
returning kernel-doc markups on each interaction
"""
- function_table = self.config.function_table
-
- if symbol:
- for s in symbol:
- function_table.add(s)
-
- # Output none mode: only warnings will be shown
- if not self.out_style:
- return
-
self.out_style.set_config(self.config)
- self.out_style.set_filter(export, internal, symbol, nosymbol,
- function_table, enable_lineno,
- no_doc_sections)
-
if not filenames:
filenames = sorted(self.results.keys())
for fname in filenames:
+ function_table = set()
+
+ if internal or export:
+ if not export_file:
+ export_file = [fname]
+
+ for f in export_file:
+ function_table |= self.export_table[f]
+
+ if symbol:
+ for s in symbol:
+ function_table.add(s)
+
+ self.out_style.set_filter(export, internal, symbol, nosymbol,
+ function_table, enable_lineno,
+ no_doc_sections)
+
msg = ""
for name, arg in self.results[fname]:
msg += self.out_msg(fname, name, arg)
@@ -260,12 +279,3 @@ class KernelFiles():
fname, ln, dtype)
if msg:
yield fname, msg
-
- @property
- def errors(self):
- """
- Return a count of the number of warnings found, including
- the ones displayed while interacting over self.msg.
- """
-
- return self.config.errors
diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
index 487068753b53..c07ca749a82f 100755
--- a/scripts/lib/kdoc/kdoc_output.py
+++ b/scripts/lib/kdoc/kdoc_output.py
@@ -68,7 +68,7 @@ class OutputFormat:
self.enable_lineno = None
self.nosymbol = {}
self.symbol = None
- self.function_table = set()
+ self.function_table = None
self.config = None
self.no_doc_sections = False
@@ -93,10 +93,10 @@ class OutputFormat:
self.enable_lineno = enable_lineno
self.no_doc_sections = no_doc_sections
+ self.function_table = function_table
if symbol:
self.out_mode = self.OUTPUT_INCLUDE
- function_table = symbol
elif export:
self.out_mode = self.OUTPUT_EXPORTED
elif internal:
@@ -107,8 +107,6 @@ class OutputFormat:
if nosymbol:
self.nosymbol = set(nosymbol)
- if function_table:
- self.function_table = function_table
def highlight_block(self, block):
"""
@@ -128,8 +126,7 @@ class OutputFormat:
warnings = args.get('warnings', [])
for log_msg in warnings:
- self.config.log.warning(log_msg)
- self.config.errors += 1
+ self.config.warning(log_msg)
def check_doc(self, name, args):
"""Check if DOC should be output"""
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
index cf4bf7cedcbc..7c8fdb469676 100755
--- a/scripts/lib/kdoc/kdoc_parser.py
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -1132,21 +1132,25 @@ class KernelDoc:
self.emit_warning(ln, "error: Cannot parse typedef!")
@staticmethod
- def process_export(function_table, line):
+ def process_export(function_set, line):
"""
process EXPORT_SYMBOL* tags
- This method is called both internally and externally, so, it
- doesn't use self.
+ This method doesn't use any variable from the class, so declare it
+ with a staticmethod decorator.
"""
+ # Note: it accepts only one EXPORT_SYMBOL* per line, as having
+ # multiple export lines would violate Kernel coding style.
+
if export_symbol.search(line):
symbol = export_symbol.group(2)
- function_table.add(symbol)
+ function_set.add(symbol)
+ return
if export_symbol_ns.search(line):
symbol = export_symbol_ns.group(2)
- function_table.add(symbol)
+ function_set.add(symbol)
def process_normal(self, ln, line):
"""
@@ -1616,17 +1620,39 @@ class KernelDoc:
elif doc_content.search(line):
self.entry.contents += doc_content.group(1) + "\n"
- def run(self):
+ def parse_export(self):
+ """
+ Parses EXPORT_SYMBOL* macros from a single Kernel source file.
+ """
+
+ export_table = set()
+
+ try:
+ with open(self.fname, "r", encoding="utf8",
+ errors="backslashreplace") as fp:
+
+ for line in fp:
+ self.process_export(export_table, line)
+
+ except IOError:
+ return None
+
+ return export_table
+
+ def parse_kdoc(self):
"""
Open and process each line of a C source file.
- he parsing is controlled via a state machine, and the line is passed
+ The parsing is controlled via a state machine, and the line is passed
to a different process function depending on the state. The process
function may update the state as needed.
+
+ Besides parsing kernel-doc tags, it also parses export symbols.
"""
cont = False
prev = ""
prev_ln = None
+ export_table = set()
try:
with open(self.fname, "r", encoding="utf8",
@@ -1658,6 +1684,16 @@ class KernelDoc:
self.st_inline_name[self.inline_doc_state],
line)
+ # This is an optimization over the original script.
+ # There, when export_file was used for the same file,
+ # it was read twice. Here, we use the already-existing
+ # loop to parse exported symbols as well.
+ #
+ # TODO: It should be noticed that not all states are
+ # needed here. On a future cleanup, process export only
+ # at the states that aren't handling comment markups.
+ self.process_export(export_table, line)
+
# Hand this line to the appropriate state handler
if self.state == self.STATE_NORMAL:
self.process_normal(ln, line)
@@ -1674,3 +1710,5 @@ class KernelDoc:
self.process_docblock(ln, line)
except OSError:
self.config.log.error(f"Error: Cannot open file {self.fname}")
+
+ return export_table, self.entries
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 39/39] docs: sphinx: kerneldoc: Use python class if available
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (37 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 38/39] scripts/kernel_doc.py: better handle exported symbols Mauro Carvalho Chehab
@ 2025-02-24 9:08 ` Mauro Carvalho Chehab
2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
39 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24 9:08 UTC (permalink / raw)
To: Linux Doc Mailing List, Jonathan Corbet
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Kees Cook,
linux-kernel
Better integrate with the new kernel-doc tool by calling the
Python classes directly if KERNELDOC=scripts/kernel-doc.py.
This way, warnings won't be duplicated anymore, as files
will be parsed only once.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/sphinx/kerneldoc.py | 137 +++++++++++++++++++++++++++---
1 file changed, 125 insertions(+), 12 deletions(-)
diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py
index 344789ed9ea2..0758d49ee07c 100644
--- a/Documentation/sphinx/kerneldoc.py
+++ b/Documentation/sphinx/kerneldoc.py
@@ -41,7 +41,15 @@ import sphinx
from sphinx.util.docutils import switch_source_input
from sphinx.util import logging
+srctree = os.path.abspath(os.environ["srctree"])
+sys.path.insert(0, os.path.join(srctree, "scripts/lib/kdoc"))
+
+from kdoc_files import KernelFiles
+from kdoc_output import RestFormat
+
__version__ = '1.0'
+kfiles = None
+logger = logging.getLogger('kerneldoc')
def cmd_str(cmd):
"""
@@ -79,14 +87,30 @@ class KernelDocDirective(Directive):
'functions': directives.unchanged,
}
has_content = False
- logger = logging.getLogger('kerneldoc')
verbose = 0
- def run(self):
+ parse_args = {}
+ msg_args = {}
+
+ def handle_args(self):
+
env = self.state.document.settings.env
cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno']
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
+
+ # Arguments used by KernelFiles.parse() function
+ self.parse_args["file_list"] = [filename]
+ self.parse_args["export_file"] = []
+
+ # Arguments used by KernelFiles.msg() function
+ self.msg_args["enable_lineno"] = True
+ self.msg_args["export"] = False
+ self.msg_args["internal"] = False
+ self.msg_args["symbol"] = []
+ self.msg_args["nosymbol"] = []
+ self.msg_args["no_doc_sections"] = False
+
export_file_patterns = []
verbose = os.environ.get("V")
@@ -99,7 +123,8 @@ class KernelDocDirective(Directive):
# Tell sphinx of the dependency
env.note_dependency(os.path.abspath(filename))
- tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
+ self.tab_width = self.options.get('tab-width',
+ self.state.document.settings.tab_width)
# 'function' is an alias of 'identifiers'
if 'functions' in self.options:
@@ -109,11 +134,15 @@ class KernelDocDirective(Directive):
if 'export' in self.options:
cmd += ['-export']
export_file_patterns = str(self.options.get('export')).split()
+ self.msg_args["export"] = True
elif 'internal' in self.options:
cmd += ['-internal']
+ self.msg_args["internal"] = True
export_file_patterns = str(self.options.get('internal')).split()
elif 'doc' in self.options:
- cmd += ['-function', str(self.options.get('doc'))]
+ i = str(self.options.get('doc'))
+ cmd += ['-function', i]
+ self.msg_args["symbol"].append(i)
elif 'identifiers' in self.options:
identifiers = self.options.get('identifiers').split()
if identifiers:
@@ -123,8 +152,10 @@ class KernelDocDirective(Directive):
continue
cmd += ['-function', i]
+ self.msg_args["symbol"].append(i)
else:
cmd += ['-no-doc-sections']
+ self.msg_args["no_doc_sections"] = True
if 'no-identifiers' in self.options:
no_identifiers = self.options.get('no-identifiers').split()
@@ -135,6 +166,7 @@ class KernelDocDirective(Directive):
continue
cmd += ['-nosymbol', i]
+ self.msg_args["nosymbol"].append(i)
for pattern in export_file_patterns:
pattern = pattern.rstrip("\\").strip()
@@ -144,14 +176,32 @@ class KernelDocDirective(Directive):
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
env.note_dependency(os.path.abspath(f))
cmd += ['-export-file', f]
+ self.parse_args["export_file"].append(f)
+
+ # As parse is cached, we need to pass the export_file again,
+ # to let the msg filter to do the right thing
+
+ self.msg_args["export_file"] = self.parse_args["export_file"]
+
cmd += [filename]
+ return cmd
+
+ def run_cmd(self):
+ """
+ Execute an external kernel-doc command.
+ """
+ global logger
+
+ env = self.state.document.settings.env
+ cmd = self.handle_args()
+
if self.verbose >= 1:
print(cmd_str(cmd))
try:
- self.logger.verbose("calling kernel-doc '%s'" % (" ".join(cmd)))
+ logger.verbose("calling kernel-doc '%s'" % (" ".join(cmd)))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
@@ -161,13 +211,34 @@ class KernelDocDirective(Directive):
if p.returncode != 0:
sys.stderr.write(err)
- self.logger.warning("kernel-doc '%s' failed with return code %d"
+ logger.warning("kernel-doc '%s' failed with return code %d"
% (" ".join(cmd), p.returncode))
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
elif env.config.kerneldoc_verbosity > 0:
sys.stderr.write(err)
- lines = statemachine.string2lines(out, tab_width, convert_whitespace=True)
+ except Exception as e: # pylint: disable=W0703
+ logger.warning("kernel-doc '%s' processing failed with: %s" %
+ (" ".join(cmd), str(e)))
+ return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
+
+ node = nodes.section()
+
+ filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
+ self.parse_msg(filename, node, out, cmd)
+ return node.children
+
+ def parse_msg(self, filename, node, out, cmd):
+ """
+ Handles a kernel-doc output for a given file
+ """
+
+ global logger
+ env = self.state.document.settings.env
+
+ try:
+ lines = statemachine.string2lines(out, self.tab_width,
+ convert_whitespace=True)
result = ViewList()
lineoffset = 0;
@@ -183,20 +254,60 @@ class KernelDocDirective(Directive):
result.append(line, doc + ": " + filename, lineoffset)
lineoffset += 1
- node = nodes.section()
self.do_parse(result, node)
- return node.children
-
except Exception as e: # pylint: disable=W0703
- self.logger.warning("kernel-doc '%s' processing failed with: %s" %
- (" ".join(cmd), str(e)))
+ logger.warning("kernel-doc '%s' processing failed with: %s" %
+ (cmd_str(cmd), str(e)))
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
+ def run_kdoc(self, kfiles):
+ """
+ Execute kernel-doc classes directly instead of running as a separate
+ command.
+ """
+
+ cmd = self.handle_args()
+ env = self.state.document.settings.env
+
+ node = nodes.section()
+
+ kfiles.parse(**self.parse_args)
+ filenames = self.parse_args["file_list"]
+
+ for filename, out in kfiles.msg(**self.msg_args, filenames=filenames):
+ if self.verbose >= 1:
+ print(cmd_str(cmd))
+
+ self.parse_msg(filename, node, out, cmd)
+
+ return node.children
+
+ def run(self):
+ global kfiles
+
+ if kfiles:
+ return self.run_kdoc(kfiles)
+ else:
+ return self.run_cmd()
+
def do_parse(self, result, node):
with switch_source_input(self.state, result):
self.state.nested_parse(result, 0, node, match_titles=1)
+def setup_kfiles(app):
+ global kfiles
+
+ kerneldoc_bin = app.env.config.kerneldoc_bin
+
+ if kerneldoc_bin and kerneldoc_bin.endswith("kernel-doc.py"):
+ print("Using Python kernel-doc")
+ out_style = RestFormat()
+ kfiles = KernelFiles(out_style=out_style, logger=logger)
+ else:
+ print(f"Using {kerneldoc_bin}")
+
+
def setup(app):
app.add_config_value('kerneldoc_bin', None, 'env')
app.add_config_value('kerneldoc_srctree', None, 'env')
@@ -204,6 +315,8 @@ def setup(app):
app.add_directive('kernel-doc', KernelDocDirective)
+ app.connect('builder-inited', setup_kfiles)
+
return dict(
version = __version__,
parallel_read_safe = True,
--
2.48.1
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl
2025-02-24 9:08 ` [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl Mauro Carvalho Chehab
@ 2025-02-24 23:23 ` Jonathan Corbet
2025-02-25 6:26 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Corbet @ 2025-02-24 23:23 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Linux Doc Mailing List
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> In preparation for deprecating scripts/kernel-doc in favor of a
> new version written in Perl, rename it to scripts/kernel-doc.pl.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
> scripts/{kernel-doc => kernel-doc.pl} | 0
> 1 file changed, 0 insertions(+), 0 deletions(-)
> rename scripts/{kernel-doc => kernel-doc.pl} (100%)
>
> diff --git a/scripts/kernel-doc b/scripts/kernel-doc.pl
> similarity index 100%
> rename from scripts/kernel-doc
> rename to scripts/kernel-doc.pl
> --
> 2.48.1
A pretty tiny nit but ... this isn't bisectable. I'm not sure how
worried we are about that, but I thought I'd point it out.
jon
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
2025-02-24 9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
@ 2025-02-24 23:38 ` Jonathan Corbet
2025-02-25 7:38 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Corbet @ 2025-02-24 23:38 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Linux Doc Mailing List
Cc: Mauro Carvalho Chehab, Gustavo A. R. Silva, Mauro Carvalho Chehab,
Kees Cook, linux-hardening, linux-kernel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> Maintaining kernel-doc has been a challenge, as there aren't many
> perl developers among maintainers. Also, the logic there is too
> complex. Having lots of global variables and using pure functions
> doesn't help.
>
> Rewrite the script in Python, placing most global variables
> inside classes. This should help maintaining the script in long
> term.
[...]
> diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
> new file mode 100755
> index 000000000000..5cf5ed63f215
> --- /dev/null
> +++ b/scripts/kernel-doc.py
> @@ -0,0 +1,2757 @@
> +#!/usr/bin/env python3
> +# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
> +# pylint: disable=C0302,C0103,C0301
> +# pylint: disable=C0116,C0115,W0511,W0613
> +# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
> +# SPDX-License-Identifier: GPL-2.0
The SPDX tag is supposed to be up top, right under the shebang
I also think you should give consideration to preserving the other
copyright notices in the Perl version. A language translation doesn't
remove existing copyrights...who knows how much creativity went into
some of those regexes?
> +# TODO: implement warning filtering
> +
> +"""
> +kernel_doc
> +==========
> +
> +Print formatted kernel documentation to stdout
> +
> +Read C language source or header FILEs, extract embedded
> +documentation comments, and print formatted documentation
> +to standard output.
> +
> +The documentation comments are identified by the "/**"
> +opening comment mark.
> +
> +See Documentation/doc-guide/kernel-doc.rst for the
> +documentation comment syntax.
> +"""
> +
> +import argparse
> +import logging
> +import os
> +import re
> +import sys
> +
> +from datetime import datetime
> +from pprint import pformat
> +
> +from dateutil import tz
> +
> +# Local cache for regular expressions
> +re_cache = {}
> +
> +
> +class Re:
So I have to say this bugs me a bit ... the class is fine, but the
one-letter case-only difference from the standard "re" class is just
going to make the code harder for others to approach. "kern_re" or
something like that? Or even "kre" if you really want it to be as short
as possible.
> + """
> + Helper class to simplify regex declaration and usage,
> +
> + It calls re.compile for a given pattern. It also allows adding
> + regular expressions and define sub at class init time.
> +
> + Regular expressions can be cached via an argument, helping to speedup
> + searches.
> + """
[...]
> +
> +class KernelDoc:
> + # Parser states
> + STATE_NORMAL = 0 # normal code
> + STATE_NAME = 1 # looking for function name
> + STATE_BODY_MAYBE = 2 # body - or maybe more description
> + STATE_BODY = 3 # the body of the comment
> + STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
> + STATE_PROTO = 5 # scanning prototype
> + STATE_DOCBLOCK = 6 # documentation block
> + STATE_INLINE = 7 # gathering doc outside main block
> +
> + st_name = [
> + "NORMAL",
> + "NAME",
> + "BODY_MAYBE",
> + "BODY",
> + "BODY_WITH_BLANK_LINE",
> + "PROTO",
> + "DOCBLOCK",
> + "INLINE",
> + ]
So these ... kind of look like enums?
That's kind of it for nits ... I do have one wish that will kind of hard
to grant overall ... for the long-term maintenance of this code, it
would be really nice if every non-trivial regex were described by a
comment explaining what it is trying to do. It's not reasonable to
expect that as a condition for accepting this rewrite, but it sure would
be a nice goal to be working toward.
Thanks,
jon
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 00/39] Implement kernel-doc in Python
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
` (38 preceding siblings ...)
2025-02-24 9:08 ` [PATCH v2 39/39] docs: sphinx: kerneldoc: Use python class if available Mauro Carvalho Chehab
@ 2025-02-24 23:49 ` Jonathan Corbet
2025-02-25 7:54 ` Mauro Carvalho Chehab
39 siblings, 1 reply; 50+ messages in thread
From: Jonathan Corbet @ 2025-02-24 23:49 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Linux Doc Mailing List
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Gustavo A. R. Silva, Arnd Bergmann, Bingbu Cao,
Greg Kroah-Hartman, Kees Cook, Sakari Ailus, Takashi Sakamoto,
Tianshu Qiu, linux-arch, linux-hardening, linux-media,
linux-staging, linux1394-devel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> Hi Jon,
>
> This changeset contains the kernel-doc.py script to replace the verable
> kernel-doc originally written in Perl. It replaces the first version and the
> second series I sent on the top of it.
I've sent minor comments on a couple of the patches. The new version
works for me, I can't find any real problems with it.
Here's the question: what were your thoughts on when to do this? I can
certainly take the initial fixup patches and get them out of your queue,
but at some point there will be a need to dive into the deep end. I'm
just a bit leery of doing that as we head toward -rc5... what do you
think of "just after the merge window"?
I'm definitely looking forward to no longer having to bash my head
against the Perl version...
Thanks,
jon
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl
2025-02-24 23:23 ` Jonathan Corbet
@ 2025-02-25 6:26 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-25 6:26 UTC (permalink / raw)
To: Jonathan Corbet; +Cc: Linux Doc Mailing List, linux-kernel
Em Mon, 24 Feb 2025 16:23:21 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
>
> > In preparation for deprecating scripts/kernel-doc in favor of a
> > new version written in Perl, rename it to scripts/kernel-doc.pl.
> >
> > Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> > ---
> > scripts/{kernel-doc => kernel-doc.pl} | 0
> > 1 file changed, 0 insertions(+), 0 deletions(-)
> > rename scripts/{kernel-doc => kernel-doc.pl} (100%)
> >
> > diff --git a/scripts/kernel-doc b/scripts/kernel-doc.pl
> > similarity index 100%
> > rename from scripts/kernel-doc
> > rename to scripts/kernel-doc.pl
> > --
> > 2.48.1
>
> A pretty tiny nit but ... this isn't bisectable. I'm not sure how
> worried we are about that, but I thought I'd point it out.
I wrote this in separate to make the diff clear that this patch
just renames the script without any changes. This helps you to
review.
When applying it, I would merge this one with the next patch, to
prevent bisect issues.
Thanks,
Mauro
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
2025-02-24 23:38 ` Jonathan Corbet
@ 2025-02-25 7:38 ` Mauro Carvalho Chehab
2025-02-25 20:10 ` Jonathan Corbet
0 siblings, 1 reply; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-25 7:38 UTC (permalink / raw)
To: Jonathan Corbet; +Cc: Linux Doc Mailing List, linux-hardening, linux-kernel
Em Mon, 24 Feb 2025 16:38:58 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
>
> > Maintaining kernel-doc has been a challenge, as there aren't many
> > perl developers among maintainers. Also, the logic there is too
> > complex. Having lots of global variables and using pure functions
> > doesn't help.
> >
> > Rewrite the script in Python, placing most global variables
> > inside classes. This should help maintaining the script in long
> > term.
>
> [...]
>
> > diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
> > new file mode 100755
> > index 000000000000..5cf5ed63f215
> > --- /dev/null
> > +++ b/scripts/kernel-doc.py
> > @@ -0,0 +1,2757 @@
> > +#!/usr/bin/env python3
> > +# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
> > +# pylint: disable=C0302,C0103,C0301
> > +# pylint: disable=C0116,C0115,W0511,W0613
> > +# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
> > +# SPDX-License-Identifier: GPL-2.0
>
> The SPDX tag is supposed to be up top, right under the shebang
I'll move it.
>
> I also think you should give consideration to preserving the other
> copyright notices in the Perl version. A language translation doesn't
> remove existing copyrights...who knows how much creativity went into
> some of those regexes?
Makes sense, but the copyrights at kernel-doc.pl:
## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
## Copyright (C) 2001 Simon Huggins ##
## Copyright (C) 2005-2012 Randy Dunlap ##
## Copyright (C) 2012 Dan Luedtke ##
## ##
## #define enhancements by Armin Kuster <akuster@mvista.com> ##
## Copyright (c) 2000 MontaVista Software, Inc. ##
#
# Copyright (C) 2022 Tomasz Warniełło (POD)
Also doesn't preserve all copyrights from people that worked hard to
maintain it all over those years.
A quick check with git log shows 68 different authors touching it
(didn't check how trivial/hard were the changes):
$ git log --follow --pretty="%an" scripts/kernel-doc.pl|sort|uniq -c|sort -n
1 Alexander A. Klimov
1 Alexander Lobakin
1 Anna-Maria Behnsen
1 Bart Van Assche
1 Chen-Yu Tsai
1 Coco Li
1 Dan Luedtke
1 Donald Hunter
1 Gabriel Krisman Bertazi
1 Greg Kroah-Hartman
1 Harvey Harrison
1 Horia Geanta
1 Jason Gunthorpe
1 Jérémy Bobbio
1 Johannes Weiner
1 Jonathan Cameron
1 Kamil Rytarowski
1 Laurent Pinchart
1 Levin, Alexander (Sasha Levin)
1 Linus Torvalds
1 Lucas De Marchi
1 Mark Rutland
1 Masahiro Yamada
1 Michal Wajdeczko
1 Niklas Söderlund
1 Nishanth Menon
1 Peter Maydell
1 Pierre-Louis Bossart
1 Randy.Dunlap
1 Richard Kennedy
1 Rich Walker
1 Rolf Eike Beer
1 Silvio Fricke
1 Utkarsh Tripathi
1 valdis.kletnieks@vt.edu
1 Will Deacon
2 Ilya Dryomov
2 Jakub Kicinski
2 Jason Baron
2 Jonathan Neuschäfer
2 Markus Heiser
2 Pavan Kumar Linga
2 Pavel Pisa
2 Sakari Ailus
2 Yacine Belkadi
2 Yujie Liu
3 Akira Yokosawa
3 André Almeida
3 Andy Shevchenko
3 Ben Hutchings
3 Borislav Petkov
3 Conchúr Navid
3 Daniel Santos
3 Danilo Cesar Lemes de Paula
3 Mike Rapoport
4 Daniel Vetter
4 Matthew Wilcox
5 Martin Waitz
5 Paolo Bonzini
6 Aditya Srivastava
6 Vegard Nossum
7 Kees Cook
11 Johannes Berg
11 Tomasz Warniełło
20 Jonathan Corbet
32 Jani Nikula
57 Mauro Carvalho Chehab
65 Randy Dunlap
So, picking the latest e-mails from the above authors, maybe we can add
some credit lines like these:
# Converted from the kernel-doc script originally written in Perl
# under GPLv2, copyrighted since 1998 by the following authors:
#
# Aditya Srivastava <yashsri421@gmail.com>
# Akira Yokosawa <akiyks@gmail.com>
# Alexander A. Klimov <grandmaster@al2klimov.de>
# Alexander Lobakin <aleksander.lobakin@intel.com>
# André Almeida <andrealmeid@igalia.com>
# Andy Shevchenko <andriy.shevchenko@linux.intel.com>
# Anna-Maria Behnsen <anna-maria@linutronix.de>
# Armin Kuster <akuster@mvista.com>
# Bart Van Assche <bart.vanassche@sandisk.com>
# Ben Hutchings <ben@decadent.org.uk>
# Borislav Petkov <bbpetkov@yahoo.de>
# Chen-Yu Tsai <wenst@chromium.org>
# Coco Li <lixiaoyan@google.com>
# Conchúr Navid <conchur@web.de>
# Daniel Santos <daniel.santos@pobox.com>
# Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
# Dan Luedtke <mail@danrl.de>
# Donald Hunter <donald.hunter@gmail.com>
# Gabriel Krisman Bertazi <krisman@collabora.co.uk>
# Greg Kroah-Hartman <gregkh@linuxfoundation.org>
# Harvey Harrison <harvey.harrison@gmail.com>
# Horia Geanta <horia.geanta@freescale.com>
# Ilya Dryomov <idryomov@gmail.com>
# Jakub Kicinski <kuba@kernel.org>
# Jani Nikula <jani.nikula@intel.com>
# Jason Baron <jbaron@redhat.com>
# Jason Gunthorpe <jgg@nvidia.com>
# Jérémy Bobbio <lunar@debian.org>
# Johannes Berg <johannes.berg@intel.com>
# Johannes Weiner <hannes@cmpxchg.org>
# Jonathan Cameron <Jonathan.Cameron@huawei.com>
# Jonathan Corbet <corbet@lwn.net>
# Jonathan Neuschäfer <j.neuschaefer@gmx.net>
# Kamil Rytarowski <n54@gmx.com>
# Kees Cook <kees@kernel.org>
# Laurent Pinchart <laurent.pinchart@ideasonboard.com>
# Levin, Alexander (Sasha Levin) <alexander.levin@verizon.com>
# Linus Torvalds <torvalds@linux-foundation.org>
# Lucas De Marchi <lucas.demarchi@profusion.mobi>
# Mark Rutland <mark.rutland@arm.com>
# Markus Heiser <markus.heiser@darmarit.de>
# Martin Waitz <tali@admingilde.org>
# Masahiro Yamada <masahiroy@kernel.org>
# Matthew Wilcox <willy@infradead.org>
# Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
# Michal Wajdeczko <michal.wajdeczko@intel.com>
# Michael Zucchi
# Mike Rapoport <rppt@linux.ibm.com>
# Niklas Söderlund <niklas.soderlund@corigine.com>
# Nishanth Menon <nm@ti.com>
# Paolo Bonzini <pbonzini@redhat.com>
# Pavan Kumar Linga <pavan.kumar.linga@intel.com>
# Pavel Pisa <pisa@cmp.felk.cvut.cz>
# Peter Maydell <peter.maydell@linaro.org>
# Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
# Randy Dunlap <rdunlap@infradead.org>
# Richard Kennedy <richard@rsk.demon.co.uk>
# Rich Walker <rw@shadow.org.uk>
# Rolf Eike Beer <eike-kernel@sf-tec.de>
# Sakari Ailus <sakari.ailus@linux.intel.com>
# Silvio Fricke <silvio.fricke@gmail.com>
# Simon Huggins
# Tim Waugh <twaugh@redhat.com>
# Tomasz Warniełło <tomasz.warniello@gmail.com>
# Utkarsh Tripathi <utripathi2002@gmail.com>
# valdis.kletnieks@vt.edu <valdis.kletnieks@vt.edu>
# Vegard Nossum <vegard.nossum@oracle.com>
# Will Deacon <will.deacon@arm.com>
# Yacine Belkadi <yacine.belkadi.1@gmail.com>
# Yujie Liu <yujie.liu@intel.com>
Note: unfortunately, two of the original authors didn't send any patches
with their names since when we migrated to git. So, I'm placing them
without e-mails.
On a side note, I would keep the above credits line only at the main
kernel-doc.py, as it would be really hard to distribute it along
the several kernel-doc classes.
>
> > +# TODO: implement warning filtering
> > +
> > +"""
> > +kernel_doc
> > +==========
> > +
> > +Print formatted kernel documentation to stdout
> > +
> > +Read C language source or header FILEs, extract embedded
> > +documentation comments, and print formatted documentation
> > +to standard output.
> > +
> > +The documentation comments are identified by the "/**"
> > +opening comment mark.
> > +
> > +See Documentation/doc-guide/kernel-doc.rst for the
> > +documentation comment syntax.
> > +"""
> > +
> > +import argparse
> > +import logging
> > +import os
> > +import re
> > +import sys
> > +
> > +from datetime import datetime
> > +from pprint import pformat
> > +
> > +from dateutil import tz
> > +
> > +# Local cache for regular expressions
> > +re_cache = {}
> > +
> > +
> > +class Re:
>
> So I have to say this bugs me a bit ... the class is fine, but the
> one-letter case-only difference from the standard "re" class is just
> going to make the code harder for others to approach. "kern_re" or
> something like that? Or even "kre" if you really want it to be as short
> as possible.
A short name close to "re" made easier to convert the script ;-)
I'll rename the class to KernRe (*)
(*) I opted to follow pylint convention for class names, which
is using camel case. As we don't have classes in C, this
doesn't strictly conflicts with our Kernel conventions ;-)
To make easier, I'll do such change as a separate patch at the end
of the series.
>
> > + """
> > + Helper class to simplify regex declaration and usage,
> > +
> > + It calls re.compile for a given pattern. It also allows adding
> > + regular expressions and define sub at class init time.
> > +
> > + Regular expressions can be cached via an argument, helping to speedup
> > + searches.
> > + """
>
> [...]
>
> > +
> > +class KernelDoc:
> > + # Parser states
> > + STATE_NORMAL = 0 # normal code
> > + STATE_NAME = 1 # looking for function name
> > + STATE_BODY_MAYBE = 2 # body - or maybe more description
> > + STATE_BODY = 3 # the body of the comment
> > + STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
> > + STATE_PROTO = 5 # scanning prototype
> > + STATE_DOCBLOCK = 6 # documentation block
> > + STATE_INLINE = 7 # gathering doc outside main block
> > +
> > + st_name = [
> > + "NORMAL",
> > + "NAME",
> > + "BODY_MAYBE",
> > + "BODY",
> > + "BODY_WITH_BLANK_LINE",
> > + "PROTO",
> > + "DOCBLOCK",
> > + "INLINE",
> > + ]
>
> So these ... kind of look like enums?
Yes. I considered using Python enum there:
https://docs.python.org/3/library/enum.html
but it would simply be:
from enum import Enum
class state(enum):
NORMAL = 0 # normal code
NAME = 1 # looking for function name
BODY_MAYBE = 2 # body - or maybe more description
BODY = 3 # the body of the comment
BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
PROTO = 5 # scanning prototype
DOCBLOCK = 6 # documentation block
INLINE = 7 # gathering doc outside main block
and we would replace:
self.STATE_NORMAL
...
to:
state.NORMAL
(and a similar change for inline states as well)
Except for an ancillary number-to-string conversion with this syntax:
Color = Enum('Color', [('RED', 1), ('GREEN', 2), ('BLUE', 3)])
I didn't see much advantage of using it. See, we only use the string
on a single line, when --debug is used to show the per-line state machine.
Yet, perhaps we can split the states on a separate class anyway.
> That's kind of it for nits ... I do have one wish that will kind of hard
> to grant overall ... for the long-term maintenance of this code, it
> would be really nice if every non-trivial regex were described by a
> comment explaining what it is trying to do. It's not reasonable to
> expect that as a condition for accepting this rewrite, but it sure would
> be a nice goal to be working toward.
Agreed. For the future, the best would be to request a description for
every new regex added.
For the future, my plan is to split the C source parser (e.g. the code that
calls output_declaration() and/or modifies self.entry at the KernelDoc
class inside kdoc_parser to a separate file and class. We can then work
to implement some regexes to a more lexical way. For instance, all those
regexes:
(Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
(Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
(Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
(Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
(Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
(Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
(Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
(Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
(Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
(Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
(Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'),
(Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'),
(Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),
could be converted on a more lexical representation where the macro
name with their arguments could be represented on a clearer expression.
Something like:
ReplaceMatch("DECLARE_HASHTABLE($1, $2)", "unsigned long $1[1 << (($2) - 1)]")
We have already the NestedMatch class that do something similar to
that(*) could be improved to do things like that - or we can come up with
something new.
(*) NestedMatch currently miss one feature: it doesn't split the contents
inside parenthesis on multiple match groups. I guess it won't be hard to
add such features to it.
Thanks,
Mauro
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 00/39] Implement kernel-doc in Python
2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
@ 2025-02-25 7:54 ` Mauro Carvalho Chehab
2025-02-25 14:33 ` Jonathan Corbet
0 siblings, 1 reply; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-25 7:54 UTC (permalink / raw)
To: Jonathan Corbet
Cc: Linux Doc Mailing List, linux-kernel, Arnd Bergmann, Bingbu Cao,
Greg Kroah-Hartman, Sakari Ailus, Takashi Sakamoto, Tianshu Qiu,
linux-arch, linux-hardening, linux-media, linux-staging,
linux1394-devel
Em Mon, 24 Feb 2025 16:49:10 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
>
> > Hi Jon,
> >
> > This changeset contains the kernel-doc.py script to replace the verable
> > kernel-doc originally written in Perl. It replaces the first version and the
> > second series I sent on the top of it.
>
> I've sent minor comments on a couple of the patches. The new version
> works for me, I can't find any real problems with it.
Good!
Btw, I should have sent this earlier, but what I did here to test here were
use the new V=1 output from Sphinx kerneldoc extension to get a list of
all kernel-doc commands used to build the docs. Then, I wrote an
ancillary script to do the diff, replacing kernel-doc calls to use
the diff script. I'm enclosing the scripts I wrote with such approach,
as a patch.
Btw, I used the diff script also for the -man output, except that,
on such case, I just got all file names send them without any
arguments to -man parser.
> Here's the question: what were your thoughts on when to do this? I can
> certainly take the initial fixup patches and get them out of your queue,
> but at some point there will be a need to dive into the deep end. I'm
> just a bit leery of doing that as we head toward -rc5... what do you
> think of "just after the merge window"?
There's no need to rush things there, provided that people refrain
touching the Perl version of kernel-doc. So yeah, postponing it to
the next merge window makes sense to me. Perhaps we should announce
somewhere that we're in the process of doing such replacement, asking
people to wait for 6.15-rc before sending any changes to kernel-doc.
> I'm definitely looking forward to no longer having to bash my head
> against the Perl version...
Yeah, the Perl version have too many global symbols, which makes it
hard for people to understand it. During the conversion, I also had
to bash my head a couple of times to get things right and - as you
can see from the fixup patches on this series - sometimes I just got
things wrong and had to come up with a completely different approach
;-)
Regards,
Mauro
---
[PATCH] Test scripts to compare kernel-doc.pl with kernel-doc.py output
Those scripts are under GPLv2.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
diff --git a/check_all.sh b/check_all.sh
new file mode 100755
index 000000000000..2cc92b3c16cf
--- /dev/null
+++ b/check_all.sh
@@ -0,0 +1,1847 @@
+./diff-doc -rst -enable-lineno ./arch/s390/include/asm/debug.h
+./diff-doc -rst -enable-lineno ./arch/s390/kernel/debug.c
+./diff-doc -rst -enable-lineno ./block/blk-mq.c
+./diff-doc -rst -enable-lineno ./Documentation/gpu/rfc/i915_vm_bind.h
+./diff-doc -rst -enable-lineno ./drivers/ata/libata-eh.c
+./diff-doc -rst -enable-lineno ./drivers/base/devcoredump.c
+./diff-doc -rst -enable-lineno ./drivers/edac/edac_device.h
+./diff-doc -rst -enable-lineno ./drivers/edac/edac_mc.h
+./diff-doc -rst -enable-lineno ./drivers/edac/edac_pci.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_messages_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/intel_guc.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/pxp/intel_pxp_types.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xe/xe_assert.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_disp.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_disp.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_dp.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_dpsub.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_kms.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_kms.h
+./diff-doc -rst -enable-lineno ./drivers/i3c/device.c
+./diff-doc -rst -enable-lineno ./drivers/i3c/master.c
+./diff-doc -rst -enable-lineno ./drivers/iio/buffer/industrialio-triggered-buffer.c
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/a8293.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/af9013.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/ascot2e.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/cxd2820r.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/drxk.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/dvb-pll.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/helene.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/horus3a.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/ix2505v.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/m88ds3103.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/mb86a20s.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/mn88472.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/rtl2830.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/rtl2832.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/rtl2832_sdr.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/stb6000.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/tda10071.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/tda826x.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/zd1301_demod.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/zl10036.h
+./diff-doc -rst -enable-lineno ./drivers/media/i2c/ccs-pll.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_bridge.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_channel.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_common.c
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_demod.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_encoder.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_mux.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_pes.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_psi.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_s302m.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_ts.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_tuner.c
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_tuner.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vimc/vimc-streamer.c
+./diff-doc -rst -enable-lineno ./drivers/net/phy/phylink.c
+./diff-doc -rst -enable-lineno ./drivers/peci/core.c
+./diff-doc -rst -enable-lineno ./drivers/peci/cpu.c
+./diff-doc -rst -enable-lineno ./drivers/peci/internal.h
+./diff-doc -rst -enable-lineno ./drivers/peci/request.c
+./diff-doc -rst -enable-lineno ./drivers/platform/surface/aggregator/trace.h
+./diff-doc -rst -enable-lineno ./drivers/platform/x86/amd/wbrf.c
+./diff-doc -rst -enable-lineno ./drivers/platform/x86/intel/ifs/ifs.h
+./diff-doc -rst -enable-lineno ./drivers/scsi/scsi_proc.c
+./diff-doc -rst -enable-lineno ./drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
+./diff-doc -rst -enable-lineno ./drivers/tty/tty_ioctl.c
+./diff-doc -rst -enable-lineno -export ./arch/sh/boards/mach-x3proto/ilsel.c
+./diff-doc -rst -enable-lineno -export ./arch/sh/kernel/cpu/sh4/sq.c
+./diff-doc -rst -enable-lineno -export ./arch/x86/kernel/cpu/mtrr/mtrr.c
+./diff-doc -rst -enable-lineno -export ./arch/x86/lib/usercopy_32.c
+./diff-doc -rst -enable-lineno -export ./block/bdev.c
+./diff-doc -rst -enable-lineno -export ./block/bio.c
+./diff-doc -rst -enable-lineno -export ./block/blk-core.c
+./diff-doc -rst -enable-lineno -export ./block/blk-flush.c
+./diff-doc -rst -enable-lineno -export ./block/blk-integrity.c
+./diff-doc -rst -enable-lineno -export ./block/blk-lib.c
+./diff-doc -rst -enable-lineno -export ./block/blk-map.c
+./diff-doc -rst -enable-lineno -export ./block/blk-settings.c
+./diff-doc -rst -enable-lineno -export ./block/genhd.c
+./diff-doc -rst -enable-lineno -export ./drivers/ata/libata-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/ata/libata-scsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/class.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/component.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/dd.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/devres.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/platform.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/syscore.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/transport_class.c
+./diff-doc -rst -enable-lineno -export ./drivers/char/misc.c
+./diff-doc -rst -enable-lineno -export ./drivers/clk/clk_kunit_helpers.c
+./diff-doc -rst -enable-lineno -export ./drivers/counter/counter-chrdev.c
+./diff-doc -rst -enable-lineno -export ./drivers/counter/counter-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/devfreq/devfreq.c
+./diff-doc -rst -enable-lineno -export ./drivers/devfreq/devfreq-event.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-fence-array.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-fence-chain.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-resv.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/sync_file.c
+./diff-doc -rst -enable-lineno -export ./drivers/firewire/core-device.c
+./diff-doc -rst -enable-lineno -export ./drivers/firewire/core-iso.c
+./diff-doc -rst -enable-lineno -export ./drivers/firewire/core-transaction.c
+./diff-doc -rst -enable-lineno -export ./drivers/firmware/dmi_scan.c
+./diff-doc -rst -enable-lineno -export ./drivers/firmware/stratix10-svc.c
+./diff-doc -rst -enable-lineno -export ./drivers/firmware/sysfb.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-acpi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-devres.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-of.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/bridge/panel.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_bridge_connector.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_cec.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dsc_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_hdcp_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_scdc_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic_state_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic_uapi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_auth.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_blend.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_buddy.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_cache.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_client.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_client_event.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_client_modeset.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_color_mgmt.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_crtc.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_crtc_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_damage_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_debugfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_debugfs_crc.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_drv.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_edid.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_eld.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_encoder.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_exec.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_fb_dma_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_fb_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_file.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_flip_work.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_format_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_fourcc.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_framebuffer.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_atomic_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_dma_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_framebuffer_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_shmem_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_ttm_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_vram_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_ioc32.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_ioctl.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_managed.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mipi_dbi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mipi_dsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mm.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mode_config.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mode_object.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_modes.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_modeset_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_modeset_lock.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_of.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panel_backlight_quirks.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panel.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panel_orientation_quirks.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panic.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_plane_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_prime.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_print.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_privacy_screen.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_probe_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_property.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_rect.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_self_refresh_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_simple_kms_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_syncobj.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_vblank.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_vblank_work.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_vma_manager.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_writeback.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/scheduler/sched_entity.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/scheduler/sched_main.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_device.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_pool.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_resource.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_tt.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/host1x/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/host1x/syncpt.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -export ./drivers/hsi/hsi_core.c
+./diff-doc -rst -enable-lineno -export ./drivers/i2c/i2c-core-base.c
+./diff-doc -rst -enable-lineno -export ./drivers/i2c/i2c-core-smbus.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/buffer/industrialio-hw-consumer.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/industrialio-buffer.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/industrialio-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/industrialio-trigger.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/cm.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/cq.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/packer.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/rw.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/sa_query.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/ud_header.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/umem.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/umem_odp.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/verbs.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/ah.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/cq.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/mcast.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/mr.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/qp.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/rc.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/vt.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/ff-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/ff-memless.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/input.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/input-mt.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/serio/libps2.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/sparse-keymap.c
+./diff-doc -rst -enable-lineno -export ./drivers/iommu/iommufd/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/iommu/iommufd/main.c
+./diff-doc -rst -enable-lineno -export ./drivers/media/v4l2-core/v4l2-jpeg.c
+./diff-doc -rst -enable-lineno -export ./drivers/message/fusion/mptbase.c
+./diff-doc -rst -enable-lineno -export ./drivers/message/fusion/mptscsih.c
+./diff-doc -rst -enable-lineno -export ./drivers/mtd/nand/raw/nand_base.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/mdio_bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy-c45.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy_device.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/sfp-bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/nvmem/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/address.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/base.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/dynamic.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/fdt.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/irq.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/of_kunit_helpers.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/overlay.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/platform.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/property.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/resolver.c
+./diff-doc -rst -enable-lineno -export ./drivers/parport/ieee1284.c
+./diff-doc -rst -enable-lineno -export ./drivers/parport/share.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/access.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/devres.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/hotplug/pci_hotplug_core.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/iomap.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/iov.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/irq.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/msi/api.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/msi/msi.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/p2pdma.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/pci.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/pci-driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/probe.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/remove.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/rom.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/search.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/slot.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/tph.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/vgaarb.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/controller.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/ssh_packet_layer.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/surface_acpi_notify.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/x86/wmi.c
+./diff-doc -rst -enable-lineno -export ./drivers/pnp/card.c
+./diff-doc -rst -enable-lineno -export ./drivers/pnp/manager.c
+./diff-doc -rst -enable-lineno -export ./drivers/pnp/support.c
+./diff-doc -rst -enable-lineno -export ./drivers/power/sequencing/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/pwm/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/rapidio/rio.c
+./diff-doc -rst -enable-lineno -export ./drivers/rapidio/rio-driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/regulator/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/airq.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/ccwgroup.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/cmf.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/device_ops.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/hosts.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/iscsi_boot_sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/libiscsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/libiscsi_tcp.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsicam.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_common.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_devinfo.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_error.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_ioctl.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_lib.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_lib_dma.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_scan.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_fc.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_iscsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_sas.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_spi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_srp.c
+./diff-doc -rst -enable-lineno -export ./drivers/sh/maple/maple.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/messaging.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/sched.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/stream.c
+./diff-doc -rst -enable-lineno -export ./drivers/spi/spi.c
+./diff-doc -rst -enable-lineno -export ./drivers/staging/vme_user/vme.c
+./diff-doc -rst -enable-lineno -export ./drivers/target/target_core_transport.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/n_tty.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/serial/8250/8250_core.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/vt/selection.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/vt/vt.c
+./diff-doc -rst -enable-lineno -export ./drivers/uio/uio.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/common/common.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/file.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/hcd.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/hcd-pci.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/hub.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/message.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/urb.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/usb.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/gadget/composite.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/gadget/config.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/gadget/usbstring.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/aperture.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/backlight/backlight.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/core/fbcmap.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/core/fbmem.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/core/modedb.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/macmodes.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/hdmi.c
+./diff-doc -rst -enable-lineno -export ./drivers/w1/w1_family.c
+./diff-doc -rst -enable-lineno -export ./drivers/w1/w1_int.c
+./diff-doc -rst -enable-lineno -export ./drivers/w1/w1_io.c
+./diff-doc -rst -enable-lineno -export -export-file ./drivers/misc/mei/bus.c ./drivers/misc/mei/bus.c
+./diff-doc -rst -enable-lineno -export ./fs/anon_inodes.c
+./diff-doc -rst -enable-lineno -export ./fs/attr.c
+./diff-doc -rst -enable-lineno -export ./fs/bad_inode.c
+./diff-doc -rst -enable-lineno -export ./fs/buffer.c
+./diff-doc -rst -enable-lineno -export ./fs/char_dev.c
+./diff-doc -rst -enable-lineno -export ./fs/dax.c
+./diff-doc -rst -enable-lineno -export ./fs/dcache.c
+./diff-doc -rst -enable-lineno -export ./fs/debugfs/file.c
+./diff-doc -rst -enable-lineno -export ./fs/debugfs/inode.c
+./diff-doc -rst -enable-lineno -export ./fs/d_path.c
+./diff-doc -rst -enable-lineno -export ./fs/eventfd.c
+./diff-doc -rst -enable-lineno -export ./fs/filesystems.c
+./diff-doc -rst -enable-lineno -export ./fs/fs-writeback.c
+./diff-doc -rst -enable-lineno -export ./fs/inode.c
+./diff-doc -rst -enable-lineno -export ./fs/jbd2/journal.c
+./diff-doc -rst -enable-lineno -export ./fs/libfs.c
+./diff-doc -rst -enable-lineno -export ./fs/locks.c
+./diff-doc -rst -enable-lineno -export ./fs/mpage.c
+./diff-doc -rst -enable-lineno -export ./fs/namei.c
+./diff-doc -rst -enable-lineno -export ./fs/namespace.c
+./diff-doc -rst -enable-lineno -export ./fs/posix_acl.c
+./diff-doc -rst -enable-lineno -export ./fs/pstore/blk.c
+./diff-doc -rst -enable-lineno -export ./fs/seq_file.c
+./diff-doc -rst -enable-lineno -export ./fs/stat.c
+./diff-doc -rst -enable-lineno -export ./fs/super.c
+./diff-doc -rst -enable-lineno -export ./fs/sync.c
+./diff-doc -rst -enable-lineno -export ./fs/sysfs/file.c
+./diff-doc -rst -enable-lineno -export ./fs/sysfs/symlink.c
+./diff-doc -rst -enable-lineno -export ./fs/xattr.c
+./diff-doc -rst -enable-lineno -export ./kernel/audit.c
+./diff-doc -rst -enable-lineno -export ./kernel/cgroup/dmem.c
+./diff-doc -rst -enable-lineno -export ./kernel/dma.c
+./diff-doc -rst -enable-lineno -export ./kernel/dma/mapping.c
+./diff-doc -rst -enable-lineno -export ./kernel/irq/chip.c
+./diff-doc -rst -enable-lineno -export ./kernel/irq/generic-chip.c
+./diff-doc -rst -enable-lineno -export ./kernel/kthread.c
+./diff-doc -rst -enable-lineno -export ./kernel/livepatch/core.c
+./diff-doc -rst -enable-lineno -export ./kernel/livepatch/shadow.c
+./diff-doc -rst -enable-lineno -export ./kernel/livepatch/state.c
+./diff-doc -rst -enable-lineno -export ./kernel/locking/mutex.c
+./diff-doc -rst -enable-lineno -export ./kernel/module/kmod.c
+./diff-doc -rst -enable-lineno -export ./kernel/panic.c
+./diff-doc -rst -enable-lineno -export ./kernel/power/energy_model.c
+./diff-doc -rst -enable-lineno -export ./kernel/relay.c
+./diff-doc -rst -enable-lineno -export ./kernel/resource.c
+./diff-doc -rst -enable-lineno -export ./kernel/sched/core.c
+./diff-doc -rst -enable-lineno -export ./kernel/sched/wait.c
+./diff-doc -rst -enable-lineno -export ./kernel/sysctl.c
+./diff-doc -rst -enable-lineno -export ./kernel/time/hrtimer.c
+./diff-doc -rst -enable-lineno -export ./kernel/time/time.c
+./diff-doc -rst -enable-lineno -export ./kernel/time/timer.c
+./diff-doc -rst -enable-lineno -export ./lib/bitmap.c
+./diff-doc -rst -enable-lineno -export ./lib/cmdline.c
+./diff-doc -rst -enable-lineno -export ./lib/crc16.c
+./diff-doc -rst -enable-lineno -export ./lib/crc4.c
+./diff-doc -rst -enable-lineno -export ./lib/crc7.c
+./diff-doc -rst -enable-lineno -export ./lib/crc8.c
+./diff-doc -rst -enable-lineno -export ./lib/crc-ccitt.c
+./diff-doc -rst -enable-lineno -export ./lib/crc-itu-t.c
+./diff-doc -rst -enable-lineno -export ./lib/kobject.c
+./diff-doc -rst -enable-lineno -export ./lib/kstrtox.c
+./diff-doc -rst -enable-lineno -export ./lib/kunit/platform.c
+./diff-doc -rst -enable-lineno -export ./lib/list_sort.c
+./diff-doc -rst -enable-lineno -export ./lib/math/gcd.c
+./diff-doc -rst -enable-lineno -export ./lib/math/int_pow.c
+./diff-doc -rst -enable-lineno -export ./lib/math/int_sqrt.c
+./diff-doc -rst -enable-lineno -export ./lib/parser.c
+./diff-doc -rst -enable-lineno -export ./lib/reed_solomon/reed_solomon.c
+./diff-doc -rst -enable-lineno -export ./lib/refcount.c
+./diff-doc -rst -enable-lineno -export ./lib/sort.c
+./diff-doc -rst -enable-lineno -export ./lib/string.c
+./diff-doc -rst -enable-lineno -export ./lib/string_helpers.c
+./diff-doc -rst -enable-lineno -export ./lib/textsearch.c
+./diff-doc -rst -enable-lineno -export ./lib/uuid.c
+./diff-doc -rst -enable-lineno -export ./lib/vsprintf.c
+./diff-doc -rst -enable-lineno -export ./mm/dmapool.c
+./diff-doc -rst -enable-lineno -export ./mm/filemap.c
+./diff-doc -rst -enable-lineno -export ./mm/memory.c
+./diff-doc -rst -enable-lineno -export ./mm/mempool.c
+./diff-doc -rst -enable-lineno -export ./mm/page-writeback.c
+./diff-doc -rst -enable-lineno -export ./mm/readahead.c
+./diff-doc -rst -enable-lineno -export ./mm/slab_common.c
+./diff-doc -rst -enable-lineno -export ./mm/slub.c
+./diff-doc -rst -enable-lineno -export ./mm/truncate.c
+./diff-doc -rst -enable-lineno -export ./mm/vmalloc.c
+./diff-doc -rst -enable-lineno -export ./net/core/datagram.c
+./diff-doc -rst -enable-lineno -export ./net/core/dev.c
+./diff-doc -rst -enable-lineno -export ./net/core/filter.c
+./diff-doc -rst -enable-lineno -export ./net/core/gen_estimator.c
+./diff-doc -rst -enable-lineno -export ./net/core/gen_stats.c
+./diff-doc -rst -enable-lineno -export ./net/core/skbuff.c
+./diff-doc -rst -enable-lineno -export ./net/core/sock.c
+./diff-doc -rst -enable-lineno -export ./net/core/stream.c
+./diff-doc -rst -enable-lineno -export ./net/ethernet/eth.c
+./diff-doc -rst -enable-lineno -export ./net/sched/sch_generic.c
+./diff-doc -rst -enable-lineno -export ./net/socket.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/clnt.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/rpcb_clnt.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/rpc_pipe.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/sched.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/socklib.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/stats.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/svc_xprt.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/xdr.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/xprt.c
+./diff-doc -rst -enable-lineno -export -nosymbol printk ./kernel/printk/printk.c
+./diff-doc -rst -enable-lineno -export ./security/inode.c
+./diff-doc -rst -enable-lineno -export ./security/security.c
+./diff-doc -rst -enable-lineno ./fs/jbd2/transaction.c
+./diff-doc -rst -enable-lineno ./fs/netfs/buffered_read.c
+./diff-doc -rst -enable-lineno ./fs/pipe.c
+./diff-doc -rst -enable-lineno ./fs/splice.c
+./diff-doc -rst -enable-lineno -function acoustic_limit_rpm_threshold ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function acoustic_target_rpm_threshold ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Actions and configuration' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function aead_request -function aead_alg ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function ahash_request_set_tfm -function ahash_request_alloc -function ahash_request_free -function ahash_request_set_callback -function ahash_request_set_crypt ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function akcipher_alg -function akcipher_request ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function akcipher_request_alloc -function akcipher_request_free -function akcipher_request_set_callback -function akcipher_request_set_crypt ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function amdgpu_dm_atomic_check -function amdgpu_dm_atomic_commit_tail ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function amdgpu_object ./drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS debugfs control interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS debugfs EEPROM table reset interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS Reboot Behavior for Unrecoverable Errors' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS sysfs Error Count Interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS sysfs gpu_vram_bad_pages Interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function amd_ip_block_type -function amd_ip_funcs -function DC_DEBUG_MASK ./drivers/gpu/drm/amd/include/amd_shared.h
+./diff-doc -rst -enable-lineno -function 'Analog TV Connector Properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'AP support for powersaving clients' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'ARM PrimeCell PL110 and PL111 CLCD Driver' ./drivers/gpu/drm/pl111/pl111_drv.c
+./diff-doc -rst -enable-lineno -function ASSERT_EQ -function ASSERT_NE -function ASSERT_LT -function ASSERT_LE -function ASSERT_GT -function ASSERT_GE -function ASSERT_NULL -function ASSERT_TRUE -function ASSERT_NULL -function ASSERT_TRUE -function ASSERT_FALSE -function ASSERT_STREQ -function ASSERT_STRNE -function EXPECT_EQ -function EXPECT_NE -function EXPECT_LT -function EXPECT_LE -function EXPECT_GT -function EXPECT_GE -function EXPECT_NULL -function EXPECT_TRUE -function EXPECT_FALSE -function EXPECT_STREQ -function EXPECT_STRNE ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function ASSERT_EXCLUSIVE_WRITER -function ASSERT_EXCLUSIVE_WRITER_SCOPED -function ASSERT_EXCLUSIVE_ACCESS -function ASSERT_EXCLUSIVE_ACCESS_SCOPED -function ASSERT_EXCLUSIVE_BITS ./include/linux/kcsan-checks.h
+./diff-doc -rst -enable-lineno -function 'Asynchronous AEAD Request Handle' ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function 'asynchronous flip implementation' ./drivers/gpu/drm/i915/display/intel_display.c
+./diff-doc -rst -enable-lineno -function 'Asynchronous Hash Request Handle' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function 'Asynchronous Message Digest API' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function atomic ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function 'atomic plane helpers' ./drivers/gpu/drm/i915/display/intel_atomic_plane.c
+./diff-doc -rst -enable-lineno -function 'atomic state reset and initialization' ./drivers/gpu/drm/drm_atomic_state_helper.c
+./diff-doc -rst -enable-lineno -function 'Authenticated Encryption With Associated Data (AEAD) Cipher API' ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function auxiliary_device ./include/linux/auxiliary_bus.h
+./diff-doc -rst -enable-lineno -function auxiliary_device_init -function __auxiliary_device_add ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function auxiliary_driver -function module_auxiliary_driver ./include/linux/auxiliary_bus.h
+./diff-doc -rst -enable-lineno -function __auxiliary_driver_register -function auxiliary_driver_unregister ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function 'aux kms helpers' ./drivers/gpu/drm/drm_modeset_helper.c
+./diff-doc -rst -enable-lineno -function 'Backlight control' ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function 'Basic sk_buff geometry' ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -function 'batch buffer command parser' ./drivers/gpu/drm/i915/i915_cmd_parser.c
+./diff-doc -rst -enable-lineno -function 'Beacon filter support' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'bitmap bitops' ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -function 'bitmap introduction' ./lib/bitmap.c
+./diff-doc -rst -enable-lineno -function 'bitmap overview' ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -function 'Block Cipher Algorithm Definitions' ./include/linux/crypto.h
+./diff-doc -rst -enable-lineno -function board_info ./drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+./diff-doc -rst -enable-lineno -function bpf_cgroup_acquire -function bpf_cgroup_release ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_cgroup_ancestor ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_cgroup_from_id ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_acquire ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_and -function bpf_cpumask_or -function bpf_cpumask_xor ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_any_distribute -function bpf_cpumask_any_and_distribute ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_copy ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_create ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_equal -function bpf_cpumask_intersects -function bpf_cpumask_subset -function bpf_cpumask_empty -function bpf_cpumask_full ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_first -function bpf_cpumask_first_zero -function bpf_cpumask_first_and -function bpf_cpumask_test_cpu -function bpf_cpumask_weight ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_release ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_setall -function bpf_cpumask_clear ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_set_cpu -function bpf_cpumask_clear_cpu ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_test_and_set_cpu -function bpf_cpumask_test_and_clear_cpu ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_task_acquire -function bpf_task_release ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_task_from_pid ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_xdp_metadata_rx_hash ./net/core/xdp.c
+./diff-doc -rst -enable-lineno -function bpf_xdp_metadata_rx_timestamp ./net/core/xdp.c
+./diff-doc -rst -enable-lineno -function bpf_xdp_metadata_rx_vlan_tag ./net/core/xdp.c
+./diff-doc -rst -enable-lineno -function 'Branch device and port refcounting' ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -function 'Bridge enum definition' ./include/uapi/linux/if_link.h
+./diff-doc -rst -enable-lineno -function 'bridge operations' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function 'Bridge port enum definition' ./include/uapi/linux/if_link.h
+./diff-doc -rst -enable-lineno -function 'Broadcom V3D Graphics Driver' ./drivers/gpu/drm/v3d/v3d_drv.c
+./diff-doc -rst -enable-lineno -function 'Broadcom V3D MMU' ./drivers/gpu/drm/v3d/v3d_mmu.c
+./diff-doc -rst -enable-lineno -function 'Broadcom V3D scheduling' ./drivers/gpu/drm/v3d/v3d_sched.c
+./diff-doc -rst -enable-lineno -function 'Broadcom VC4 Graphics Driver' ./drivers/gpu/drm/vc4/vc4_drv.c
+./diff-doc -rst -enable-lineno -function 'Buffer Objects (BO)' ./drivers/gpu/drm/xe/xe_bo_doc.h
+./diff-doc -rst -enable-lineno -function 'buffer object tiling' ./drivers/gpu/drm/i915/gem/i915_gem_tiling.c
+./diff-doc -rst -enable-lineno -function 'Buffers allocated by the backend' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function 'Buffers allocated by the frontend driver' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function bus_type -function bus_notifier_event ./include/linux/device/bus.h
+./diff-doc -rst -enable-lineno -function 'Calling mac80211 from interrupts' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'CDCLK / RAWCLK' ./drivers/gpu/drm/i915/display/intel_cdclk.c
+./diff-doc -rst -enable-lineno -function cfg80211_ops -function vif_params -function key_params -function survey_info_flags -function survey_info -function cfg80211_beacon_data -function cfg80211_ap_settings -function station_parameters -function rate_info_flags -function rate_info -function station_info -function monitor_flags -function mpath_info_flags -function mpath_info -function bss_parameters -function ieee80211_txq_params -function cfg80211_crypto_settings -function cfg80211_auth_request -function cfg80211_assoc_request -function cfg80211_deauth_request -function cfg80211_disassoc_request -function cfg80211_ibss_params -function cfg80211_connect_params -function cfg80211_pmksa -function cfg80211_rx_mlme_mgmt -function cfg80211_auth_timeout -function cfg80211_rx_assoc_resp -function cfg80211_assoc_timeout -function cfg80211_tx_mlme_mgmt -function cfg80211_ibss_joined -function cfg80211_connect_resp_params -function cfg80211_connect_done -function cfg80211_connect_result -function cfg80211_connect_bss -function cfg80211_connect_timeout -function cfg80211_roamed -function cfg80211_disconnected -function cfg80211_ready_on_channel -function cfg80211_remain_on_channel_expired -function cfg80211_new_sta -function cfg80211_rx_mgmt -function cfg80211_mgmt_tx_status -function cfg80211_cqm_rssi_notify -function cfg80211_cqm_pktloss_notify -function cfg80211_michael_mic_failure ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function cfg80211_ssid -function cfg80211_scan_request -function cfg80211_scan_done -function cfg80211_bss -function cfg80211_inform_bss -function cfg80211_inform_bss_frame_data -function cfg80211_inform_bss_data -function cfg80211_unlink_bss -function cfg80211_find_ie -function ieee80211_bss_get_ie ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function cfg80211_testmode_alloc_reply_skb -function cfg80211_testmode_reply -function cfg80211_testmode_alloc_event_skb -function cfg80211_testmode_event ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function class ./include/linux/device/class.h
+./diff-doc -rst -enable-lineno -function color-management-caps ./drivers/gpu/drm/amd/display/dc/dc.h
+./diff-doc -rst -enable-lineno -function 'Command list validator for VC4.' ./drivers/gpu/drm/vc4/vc4_validate.c
+./diff-doc -rst -enable-lineno -function 'component helper usage recommendations' ./drivers/gpu/drm/drm_drv.c
+./diff-doc -rst -enable-lineno -function console -function cons_flags ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function console_srcu_read_flags -function console_srcu_write_flags -function console_is_registered -function for_each_console_srcu -function for_each_console ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function consw ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function 'cpu access' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function 'cpu map' ./kernel/bpf/cpumap.c
+./diff-doc -rst -enable-lineno -function 'CRC ABI' ./drivers/gpu/drm/drm_debugfs_crc.c
+./diff-doc -rst -enable-lineno -function crypto_aead_reqsize -function aead_request_set_tfm -function aead_request_alloc -function aead_request_free -function aead_request_set_callback -function aead_request_set_crypt -function aead_request_set_ad ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function crypto_alg -function cipher_alg -function compress_alg ./include/linux/crypto.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_aead -function crypto_free_aead -function crypto_aead_ivsize -function crypto_aead_authsize -function crypto_aead_blocksize -function crypto_aead_setkey -function crypto_aead_setauthsize -function crypto_aead_encrypt -function crypto_aead_decrypt ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_ahash -function crypto_free_ahash -function crypto_ahash_init -function crypto_ahash_digestsize -function crypto_ahash_reqtfm -function crypto_ahash_reqsize -function crypto_ahash_statesize -function crypto_ahash_setkey -function crypto_ahash_finup -function crypto_ahash_final -function crypto_ahash_digest -function crypto_ahash_export -function crypto_ahash_import ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_akcipher -function crypto_free_akcipher -function crypto_akcipher_set_pub_key -function crypto_akcipher_set_priv_key -function crypto_akcipher_maxsize -function crypto_akcipher_encrypt -function crypto_akcipher_decrypt ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_cipher -function crypto_free_cipher -function crypto_has_cipher -function crypto_cipher_blocksize -function crypto_cipher_setkey -function crypto_cipher_encrypt_one -function crypto_cipher_decrypt_one ./include/crypto/internal/cipher.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_kpp -function crypto_free_kpp -function crypto_kpp_set_secret -function crypto_kpp_generate_public_key -function crypto_kpp_compute_shared_secret -function crypto_kpp_maxsize ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_rng -function crypto_rng_alg -function crypto_free_rng -function crypto_rng_generate -function crypto_rng_get_bytes -function crypto_rng_reset -function crypto_rng_seedsize ./include/crypto/rng.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_shash -function crypto_free_shash -function crypto_shash_blocksize -function crypto_shash_digestsize -function crypto_shash_descsize -function crypto_shash_setkey -function crypto_shash_digest -function crypto_shash_export -function crypto_shash_import -function crypto_shash_init -function crypto_shash_update -function crypto_shash_final -function crypto_shash_finup ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_sig -function crypto_free_sig -function crypto_sig_set_pubkey -function crypto_sig_set_privkey -function crypto_sig_keysize -function crypto_sig_maxsize -function crypto_sig_digestsize -function crypto_sig_sign -function crypto_sig_verify ./include/crypto/sig.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_skcipher -function crypto_free_skcipher -function crypto_has_skcipher -function crypto_skcipher_ivsize -function crypto_skcipher_blocksize -function crypto_skcipher_setkey -function crypto_skcipher_reqtfm -function crypto_skcipher_encrypt -function crypto_skcipher_decrypt ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function crypto_skcipher_reqsize -function skcipher_request_set_tfm -function skcipher_request_alloc -function skcipher_request_free -function skcipher_request_set_callback -function skcipher_request_set_crypt ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function 'CSS-based Firmware Layout' ./drivers/gpu/drm/xe/xe_uc_fw_abi.h
+./diff-doc -rst -enable-lineno -function 'cxl core' ./drivers/cxl/core/port.c
+./diff-doc -rst -enable-lineno -function 'cxl core hdm' ./drivers/cxl/core/hdm.c
+./diff-doc -rst -enable-lineno -function 'cxl core pci' ./drivers/cxl/core/pci.c
+./diff-doc -rst -enable-lineno -function 'cxl core region' ./drivers/cxl/core/region.c
+./diff-doc -rst -enable-lineno -function 'cxl mbox' ./drivers/cxl/core/mbox.c
+./diff-doc -rst -enable-lineno -function 'cxl mem' ./drivers/cxl/mem.c
+./diff-doc -rst -enable-lineno -function 'cxl objects' ./drivers/cxl/cxl.h
+./diff-doc -rst -enable-lineno -function 'cxl pci' ./drivers/cxl/pci.c
+./diff-doc -rst -enable-lineno -function 'cxl pmem' ./drivers/cxl/core/pmem.c
+./diff-doc -rst -enable-lineno -function 'cxl port' ./drivers/cxl/port.c
+./diff-doc -rst -enable-lineno -function 'cxl registers' ./drivers/cxl/core/regs.c
+./diff-doc -rst -enable-lineno -function 'damage tracking' ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function 'Data path helpers' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'dataref and headerless skbs' ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -function 'dcp blob format' ./security/keys/trusted-keys/trusted_dcp.c
+./diff-doc -rst -enable-lineno -function 'deadline hints' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function debug_object_activate ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_assert_init ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_deactivate ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_destroy ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_free ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_init ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_init_on_stack ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function 'declare bitmap' ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -function descriptors ./include/uapi/linux/usb/functionfs.h
+./diff-doc -rst -enable-lineno -function DEVICE_LIFESPAN ./include/linux/auxiliary_bus.h
+./diff-doc -rst -enable-lineno -function device_link_state ./include/linux/device.h
+./diff-doc -rst -enable-lineno -function 'Device registration' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function __devm_fpga_mgr_register ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function __devm_fpga_mgr_register_full ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function devm_gen_pool_create ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function devm_hte_register_chip -function hte_push_ts_ns ./drivers/hte/hte.c
+./diff-doc -rst -enable-lineno -function dh -function crypto_dh_key_len -function crypto_dh_encode_key -function crypto_dh_decode_key ./include/crypto/dh.h
+./diff-doc -rst -enable-lineno -function 'DH Helper Functions' ./include/crypto/dh.h
+./diff-doc -rst -enable-lineno -function 'display driver integration' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function 'Display PLLs' ./drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+./diff-doc -rst -enable-lineno -function 'Display Refresh Rate Switching (DRRS)' ./drivers/gpu/drm/i915/display/intel_drrs.c
+./diff-doc -rst -enable-lineno -function 'dma buf device access' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function 'DMA fences overview' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function 'dma helpers' ./drivers/gpu/drm/drm_gem_dma_helper.c
+./diff-doc -rst -enable-lineno -function 'DMC Firmware Support' ./drivers/gpu/drm/i915/display/intel_dmc.c
+./diff-doc -rst -enable-lineno -function 'DMC wakelock support' ./drivers/gpu/drm/i915/display/intel_dmc_wl.c
+./diff-doc -rst -enable-lineno -function dm_hw_init -function dm_hw_fini ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function 'DM Lifecycle' ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function do_div ./include/asm-generic/div64.h
+./diff-doc -rst -enable-lineno -function 'dp cec helpers' ./drivers/gpu/drm/display/drm_dp_cec.c
+./diff-doc -rst -enable-lineno -function 'dp dual mode helpers' ./drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
+./diff-doc -rst -enable-lineno -function 'dp helpers' ./drivers/gpu/drm/display/drm_dp_helper.c
+./diff-doc -rst -enable-lineno -function DPIO ./drivers/gpu/drm/i915/display/intel_dpio_phy.c
+./diff-doc -rst -enable-lineno -function 'dp mst helper' ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -function 'driver instance overview' ./drivers/gpu/drm/drm_drv.c
+./diff-doc -rst -enable-lineno -function 'Driver limitations' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function 'Driver modes of operation in terms of display buffers used' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function 'Driver power control' ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function 'driver specific ioctls' ./drivers/gpu/drm/drm_ioctl.c
+./diff-doc -rst -enable-lineno -function 'DRM Client usage stats' ./drivers/gpu/drm/xe/xe_drm_client.c
+./diff-doc -rst -enable-lineno -function drm_dp_mst_topology_try_get_mstb -function drm_dp_mst_topology_get_mstb -function drm_dp_mst_topology_put_mstb -function drm_dp_mst_topology_try_get_port -function drm_dp_mst_topology_get_port -function drm_dp_mst_topology_put_port -function drm_dp_mst_get_mstb_malloc -function drm_dp_mst_put_mstb_malloc ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -function __drm_i915_gem_create_ext ./Documentation/gpu/rfc/i915_small_bar.h
+./diff-doc -rst -enable-lineno -function __drm_i915_memory_region_info ./Documentation/gpu/rfc/i915_small_bar.h
+./diff-doc -rst -enable-lineno -function 'drm leasing' ./drivers/gpu/drm/drm_lease.c
+./diff-doc -rst -enable-lineno -function 'drm panel' ./drivers/gpu/drm/drm_panel.c
+./diff-doc -rst -enable-lineno -function drm_pvr_create_hwrt_geom_data_args -function drm_pvr_create_hwrt_rt_data_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ctx_priority -function drm_pvr_ctx_type -function drm_pvr_static_render_context_state -function drm_pvr_static_render_context_state_format -function drm_pvr_reset_framework -function drm_pvr_reset_framework_format ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_dev_query_gpu_info -function drm_pvr_dev_query_runtime_info -function drm_pvr_dev_query_hwrt_info -function drm_pvr_dev_query_quirks -function drm_pvr_dev_query_enhancements ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_dev_query ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_heap_id -function drm_pvr_heap -function drm_pvr_dev_query_heap_info ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_bo_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_context_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_free_list_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_hwrt_dataset_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_vm_context_args -function drm_pvr_ioctl_destroy_vm_context_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_destroy_context_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_destroy_free_list_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_destroy_hwrt_dataset_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_dev_query_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_get_bo_mmap_offset_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_submit_jobs_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_vm_map_args -function drm_pvr_ioctl_vm_unmap_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_obj_array ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function DRM_PVR_OBJ_ARRAY ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_static_data_area_usage -function drm_pvr_static_data_area -function drm_pvr_dev_query_static_data_areas ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_sync_op -function drm_pvr_job_type -function drm_pvr_hwrt_data_ref -function drm_pvr_job ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'drm utils' ./include/drm/drm_util.h
+./diff-doc -rst -enable-lineno -function DSB ./drivers/gpu/drm/i915/display/intel_dsb.c
+./diff-doc -rst -enable-lineno -function 'dsc helpers' ./drivers/gpu/drm/display/drm_dsc_helper.c
+./diff-doc -rst -enable-lineno -function 'dsi bridge operations' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function 'dsi helpers' ./drivers/gpu/drm/drm_mipi_dsi.c
+./diff-doc -rst -enable-lineno -function 'dup_failed_modules - tracks duplicate failed modules' ./kernel/module/stats.c
+./diff-doc -rst -enable-lineno -function 'eBPF Syscall Commands' ./include/uapi/linux/bpf.h
+./diff-doc -rst -enable-lineno -function 'eBPF Syscall Preamble' ./include/uapi/linux/bpf.h
+./diff-doc -rst -enable-lineno -function ecdh -function crypto_ecdh_key_len -function crypto_ecdh_encode_key -function crypto_ecdh_decode_key ./include/crypto/ecdh.h
+./diff-doc -rst -enable-lineno -function 'ECDH Helper Functions' ./include/crypto/ecdh.h
+./diff-doc -rst -enable-lineno -function efi_embedded_fw_desc ./include/linux/efi_embedded_fw.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_admin_state ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_ext_state ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_ext_substate_class_num_events -function ethtool_c33_pse_ext_substate_error_condition -function ethtool_c33_pse_ext_substate_mr_pse_enable -function ethtool_c33_pse_ext_substate_option_detect_ted -function ethtool_c33_pse_ext_substate_option_vport_lim -function ethtool_c33_pse_ext_substate_ovld_detected -function ethtool_c33_pse_ext_substate_pd_dll_power_type -function ethtool_c33_pse_ext_substate_power_not_available -function ethtool_c33_pse_ext_substate_short_detected ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_pw_d_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_fec_stats ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mac_stats_src ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_cfg ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_state ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_stats ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_verify_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_module_fw_flash_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_module_power_mode ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_module_power_mode_policy ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_pause_stats ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_podl_pse_admin_state ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_podl_pse_pw_d_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function EXAMPLE ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function Examples ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function example ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function 'Execbuf (User GPU command submission)' ./drivers/gpu/drm/xe/xe_exec.c
+./diff-doc -rst -enable-lineno -function 'explicit fencing properties' ./drivers/gpu/drm/drm_atomic_uapi.c
+./diff-doc -rst -enable-lineno -function extcon_get_property ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function extcon_get_state ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function extcon_set_state ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function extcon_set_state_sync ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function fan_curve ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_minimum_pwm ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_target_temperature ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_zero_rpm_enable ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_zero_rpm_stop_temperature ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Faraday TV Encoder TVE200 DRM Driver' ./drivers/gpu/drm/tve200/tve200_drv.c
+./diff-doc -rst -enable-lineno -function 'fbdev helpers' ./drivers/gpu/drm/drm_fb_helper.c
+./diff-doc -rst -enable-lineno -function 'fence cross-driver contract' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function 'fence register handling' ./drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+./diff-doc -rst -enable-lineno -function 'fence signalling annotation' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function fiemap_extent ./include/uapi/linux/fiemap.h
+./diff-doc -rst -enable-lineno -function fiemap_extent_info ./include/linux/fiemap.h
+./diff-doc -rst -enable-lineno -function fiemap ./include/uapi/linux/fiemap.h
+./diff-doc -rst -enable-lineno -function 'fifo underrun handling' ./drivers/gpu/drm/i915/display/intel_fifo_underrun.c
+./diff-doc -rst -enable-lineno -function 'file operations' ./drivers/gpu/drm/drm_file.c
+./diff-doc -rst -enable-lineno -function firmware_fallback_sysfs ./drivers/base/firmware_loader/fallback.c
+./diff-doc -rst -enable-lineno -function 'Firmware Layout' ./drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
+./diff-doc -rst -enable-lineno -function firmware_request_cache ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function firmware_request_nowarn ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function firmware_request_platform ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function firmware_upload_register ./drivers/base/firmware_loader/sysfs_upload.c
+./diff-doc -rst -enable-lineno -function firmware_upload_unregister ./drivers/base/firmware_loader/sysfs_upload.c
+./diff-doc -rst -enable-lineno -function 'Flags for CREATE_BO' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl compute command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl fragment command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl geometry command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl transfer command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for the drm_pvr_sync_op object.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'flip utils' ./include/drm/drm_flip_work.h
+./diff-doc -rst -enable-lineno -function 'Flow Control' ./drivers/gpu/drm/scheduler/sched_main.c
+./diff-doc -rst -enable-lineno -function folio_mapping ./mm/util.c
+./diff-doc -rst -enable-lineno -function fpga_bridge_get_to_list ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_bridge ./include/linux/fpga/fpga-bridge.h
+./diff-doc -rst -enable-lineno -function fpga_bridge_ops ./include/linux/fpga/fpga-bridge.h
+./diff-doc -rst -enable-lineno -function __fpga_bridge_register ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_bridges_put ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_bridge_unregister ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_image_info_alloc ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_image_info_free ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_image_info ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function 'FPGA Manager flags' ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_manager ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_manager_info ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_manager_ops ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_mgr_get ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_mgr_put ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function __fpga_mgr_register ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function __fpga_mgr_register_full ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_mgr_states ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_mgr_unregister ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_region ./include/linux/fpga/fpga-region.h
+./diff-doc -rst -enable-lineno -function fpga_region_info ./include/linux/fpga/fpga-region.h
+./diff-doc -rst -enable-lineno -function fpga_region_program_fpga ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function __fpga_region_register ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function __fpga_region_register_full ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function fpga_region_unregister ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function 'Frame Buffer Compression (FBC)' ./drivers/gpu/drm/i915/display/intel_fbc.c
+./diff-doc -rst -enable-lineno -function 'framebuffer dma helper functions' ./drivers/gpu/drm/drm_fb_dma_helper.c
+./diff-doc -rst -enable-lineno -function 'Frame filtering' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'Frame format' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'frontbuffer tracking' ./drivers/gpu/drm/i915/display/intel_frontbuffer.c
+./diff-doc -rst -enable-lineno -function fru_id ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function fs_access -function net_access -function scope ./include/uapi/linux/landlock.h
+./diff-doc -rst -enable-lineno -function fw_iso_context_schedule_flush_completions ./include/linux/firewire.h
+./diff-doc -rst -enable-lineno -function fw_upload_err ./include/linux/firmware.h
+./diff-doc -rst -enable-lineno -function fw_upload_ops ./include/linux/firmware.h
+./diff-doc -rst -enable-lineno -function fw_upload_prog ./drivers/base/firmware_loader/sysfs_upload.h
+./diff-doc -rst -enable-lineno -function 'Generic Key-agreement Protocol Primitives API' ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function 'Generic Public Key Cipher API' ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function 'Generic Public Key Signature API' ./include/crypto/sig.h
+./diff-doc -rst -enable-lineno -function 'Generic radix trees/sparse arrays' ./include/linux/generic-radix-tree.h
+./diff-doc -rst -enable-lineno -function gen_pool_add ./include/linux/genalloc.h
+./diff-doc -rst -enable-lineno -function gen_pool_add_owner ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_alloc_algo_owner ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_alloc ./include/linux/genalloc.h
+./diff-doc -rst -enable-lineno -function gen_pool_avail ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_create ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_destroy ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_dma_alloc ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_for_each_chunk ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_free_owner ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_get ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_has_addr ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_set_algo ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_size ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_virt_to_phys ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function 'getunique and setversion story' ./drivers/gpu/drm/drm_ioctl.c
+./diff-doc -rst -enable-lineno -function get_user_pages_fast ./mm/gup.c
+./diff-doc -rst -enable-lineno -function 'Global Graphics Translation Table (GGTT)' ./drivers/gpu/drm/xe/xe_ggtt.c
+./diff-doc -rst -enable-lineno -function 'Global GTT views' ./drivers/gpu/drm/i915/i915_vma_types.h
+./diff-doc -rst -enable-lineno -function gpioevent_data -function gpioevent_request -function gpiohandle_config -function gpiohandle_data -function gpiohandle_request -function gpioline_info -function gpioline_info_changed ./include/uapi/linux/gpio.h
+./diff-doc -rst -enable-lineno -function gpio_v2_line_attr_id -function gpio_v2_line_attribute -function gpio_v2_line_changed_type -function gpio_v2_line_config -function gpio_v2_line_config_attribute -function gpio_v2_line_event -function gpio_v2_line_event_id -function gpio_v2_line_flag -function gpio_v2_line_info -function gpio_v2_line_info_changed -function gpio_v2_line_request -function gpio_v2_line_values -function gpiochip_info ./include/uapi/linux/gpio.h
+./diff-doc -rst -enable-lineno -function gpu_busy_percent ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function gpu_metrics ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function GPUVM ./drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+./diff-doc -rst -enable-lineno -function 'Graphics mux' ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function 'GSC-based Firmware Layout' ./drivers/gpu/drm/xe/xe_uc_fw_abi.h
+./diff-doc -rst -enable-lineno -function 'GT Multicast/Replicated (MCR) Register Support' ./drivers/gpu/drm/i915/gt/intel_gt_mcr.c
+./diff-doc -rst -enable-lineno -function 'GT Multicast/Replicated (MCR) Register Support' ./drivers/gpu/drm/xe/xe_gt_mcr.c
+./diff-doc -rst -enable-lineno -function 'GuC-based command submission' ./drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+./diff-doc -rst -enable-lineno -function 'GuC CTB Blob' ./drivers/gpu/drm/xe/xe_guc_ct.c
+./diff-doc -rst -enable-lineno -function GuC ./drivers/gpu/drm/i915/gt/uc/intel_guc.c
+./diff-doc -rst -enable-lineno -function 'GuC Memory Management' ./drivers/gpu/drm/i915/gt/uc/intel_guc.c
+./diff-doc -rst -enable-lineno -function 'GuC Power Conservation (PC)' ./drivers/gpu/drm/xe/xe_guc_pc.c
+./diff-doc -rst -enable-lineno -function 'handling driver private state' ./drivers/gpu/drm/drm_atomic.c
+./diff-doc -rst -enable-lineno -function 'Hardware crypto acceleration' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'Hardware workarounds' ./drivers/gpu/drm/i915/gt/intel_workarounds.c
+./diff-doc -rst -enable-lineno -function 'Hardware workarounds' ./drivers/gpu/drm/xe/xe_wa.c
+./diff-doc -rst -enable-lineno -function hash_alg_common -function ahash_alg -function shash_alg ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function 'HDMI connector properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'HDMI Output' ./drivers/gpu/drm/meson/meson_dw_hdmi.c
+./diff-doc -rst -enable-lineno -function hid_bpf_ctx ./include/linux/hid_bpf.h
+./diff-doc -rst -enable-lineno -function hid_bpf_get_data ./drivers/hid/bpf/hid_bpf_dispatch.c
+./diff-doc -rst -enable-lineno -function hid_bpf_hw_request -function hid_bpf_hw_output_report -function hid_bpf_input_report -function hid_bpf_try_input_report -function hid_bpf_allocate_context -function hid_bpf_release_context ./drivers/hid/bpf/hid_bpf_dispatch.c
+./diff-doc -rst -enable-lineno -function hid_bpf_ops ./include/linux/hid_bpf.h
+./diff-doc -rst -enable-lineno -function 'HID quirks' ./include/linux/hid.h
+./diff-doc -rst -enable-lineno -function 'High Definition Audio over HDMI and Display Port' ./drivers/gpu/drm/i915/display/intel_audio.c
+./diff-doc -rst -enable-lineno -function Hotplug ./drivers/gpu/drm/i915/display/intel_hotplug.c
+./diff-doc -rst -enable-lineno -function 'hotspot properties' ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function hte_init_line_attr -function hte_ts_get -function hte_ts_put -function devm_hte_request_ts_ns -function hte_request_ts_ns -function hte_enable_ts -function hte_disable_ts -function of_hte_req_count -function hte_get_clk_src_info ./drivers/hte/hte.c
+./diff-doc -rst -enable-lineno -function HuC ./drivers/gpu/drm/i915/gt/uc/intel_huc.c
+./diff-doc -rst -enable-lineno -function 'HuC Memory Management' ./drivers/gpu/drm/i915/gt/uc/intel_huc.c
+./diff-doc -rst -enable-lineno -function hwmon ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function i2c_register_board_info ./drivers/i2c/i2c-boardinfo.c
+./diff-doc -rst -enable-lineno -function 'i915_context_create and i915_context_free tracepoints' ./drivers/gpu/drm/i915/i915_trace.h
+./diff-doc -rst -enable-lineno -function i915_context_engines_parallel_submit ./include/uapi/drm/i915_drm.h
+./diff-doc -rst -enable-lineno -function i915_oa_ops ./drivers/gpu/drm/i915/i915_perf_types.h
+./diff-doc -rst -enable-lineno -function i915_oa_poll_wait ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_read ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_stream_disable ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_stream_enable ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_stream_init ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_wait_unlocked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_add_config_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_destroy_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_disable_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_enable_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_fini ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'i915 Perf History and Comparison with Core Perf' ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_init ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_open_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_open_ioctl_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'i915 Perf Overview' ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_poll ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_poll_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_read ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_register ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_release ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_remove_config_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_stream ./drivers/gpu/drm/i915/i915_perf_types.h
+./diff-doc -rst -enable-lineno -function i915_perf_stream_ops ./drivers/gpu/drm/i915/i915_perf_types.h
+./diff-doc -rst -enable-lineno -function i915_perf_unregister ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'i915_ppgtt_create and i915_ppgtt_release tracepoints' ./drivers/gpu/drm/i915/i915_trace.h
+./diff-doc -rst -enable-lineno -function i915_sched_engine ./drivers/gpu/drm/i915/i915_scheduler_types.h
+./diff-doc -rst -enable-lineno -function 'IDA description' ./lib/idr.c
+./diff-doc -rst -enable-lineno -function 'idr sync' ./include/linux/idr.h
+./diff-doc -rst -enable-lineno -function ieee80211_ampdu_mlme_action ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_beacon_loss ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_channel_flags -function ieee80211_channel -function ieee80211_rate_flags -function ieee80211_rate -function ieee80211_sta_ht_cap -function ieee80211_supported_band -function cfg80211_signal_type -function wiphy_params_flags -function wiphy_flags -function wiphy -function wireless_dev -function wiphy_new -function wiphy_read_of_freq_limits -function wiphy_register -function wiphy_unregister -function wiphy_free -function wiphy_name -function wiphy_dev -function wiphy_priv -function priv_to_wiphy -function set_wiphy_dev -function wdev_priv -function ieee80211_iface_limit -function ieee80211_iface_combination -function cfg80211_check_combinations ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_channel_to_frequency -function ieee80211_frequency_to_channel -function ieee80211_get_channel -function ieee80211_get_response_rate -function ieee80211_hdrlen -function ieee80211_get_hdrlen_from_skb -function ieee80211_radiotap_iterator ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_conf -function ieee80211_conf_flags ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_data_to_8023 -function ieee80211_amsdu_to_8023s -function cfg80211_classify8021d ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_filter_flags ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_get_buffered_bc -function ieee80211_beacon_get -function ieee80211_sta_eosp -function ieee80211_frame_release_type -function ieee80211_sta_ps_transition -function ieee80211_sta_ps_transition_ni -function ieee80211_sta_set_buffered -function ieee80211_sta_block_awake ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_get_tx_led_name -function ieee80211_get_rx_led_name -function ieee80211_get_assoc_led_name -function ieee80211_get_radio_led_name -function ieee80211_tpt_blink -function ieee80211_tpt_led_trigger_flags -function ieee80211_create_tpt_led_trigger ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_hw -function ieee80211_hw_flags -function SET_IEEE80211_DEV -function SET_IEEE80211_PERM_ADDR -function ieee80211_ops -function ieee80211_alloc_hw -function ieee80211_register_hw -function ieee80211_unregister_hw -function ieee80211_free_hw ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_iterate_active_interfaces -function ieee80211_iterate_active_interfaces_atomic ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_queue_work -function ieee80211_queue_delayed_work ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_request_smps -function ieee80211_smps_mode ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_rx_status -function mac80211_rx_encoding_flags -function mac80211_rx_flags -function mac80211_tx_info_flags -function mac80211_tx_control_flags -function mac80211_rate_control_flags -function ieee80211_tx_rate -function ieee80211_tx_info -function ieee80211_tx_info_clear_status -function ieee80211_rx -function ieee80211_rx_ni -function ieee80211_rx_irqsafe -function ieee80211_tx_status_skb -function ieee80211_tx_status_ni -function ieee80211_tx_status_irqsafe -function ieee80211_rts_get -function ieee80211_rts_duration -function ieee80211_ctstoself_get -function ieee80211_ctstoself_duration -function ieee80211_generic_frame_duration -function ieee80211_wake_queue -function ieee80211_stop_queue -function ieee80211_wake_queues -function ieee80211_stop_queues -function ieee80211_queue_stopped ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_scan_completed ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_sta -function sta_notify_cmd -function ieee80211_find_sta -function ieee80211_find_sta_by_ifaddr ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_start_tx_ba_session -function ieee80211_start_tx_ba_cb_irqsafe -function ieee80211_stop_tx_ba_session -function ieee80211_stop_tx_ba_cb_irqsafe -function ieee80211_rate_control_changed -function ieee80211_tx_rate_control ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_tx_queue_params ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_vif ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'implementing nonblocking commit' ./drivers/gpu/drm/drm_atomic_helper.c
+./diff-doc -rst -enable-lineno -function 'implicit fence polling' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function intel_guc_allocate_vma ./drivers/gpu/drm/i915/gt/uc/intel_guc.c
+./diff-doc -rst -enable-lineno -function 'Intel GVT-g guest support' ./drivers/gpu/drm/i915/i915_vgpu.c
+./diff-doc -rst -enable-lineno -function 'Intel GVT-g host support' ./drivers/gpu/drm/i915/intel_gvt.c
+./diff-doc -rst -enable-lineno -function intel_huc_auth ./drivers/gpu/drm/i915/gt/uc/intel_huc.c
+./diff-doc -rst -enable-lineno -function intel_irq_init -function intel_irq_init_hw -function intel_hpd_init ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function intel_irq_resume ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function intel_irq_suspend ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function Interrupt ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function 'Interrupt Handling' ./drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+./diff-doc -rst -enable-lineno -function 'interrupt handling' ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function 'Interrupt management for the V3D engine' ./drivers/gpu/drm/v3d/v3d_irq.c
+./diff-doc -rst -enable-lineno -function 'Interrupt management for the V3D engine' ./drivers/gpu/drm/vc4/vc4_irq.c
+./diff-doc -rst -enable-lineno -function Introduction ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'IOCTL validation helpers' ./drivers/gpu/drm/imagination/pvr_device.h
+./diff-doc -rst -enable-lineno -function 'IP Blocks' ./drivers/gpu/drm/amd/include/amd_shared.h
+./diff-doc -rst -enable-lineno -function iscsi_iser_pdu_alloc -function iser_initialize_task_headers -function \ -function iscsi_iser_task_init -function iscsi_iser_mtask_xmit -function iscsi_iser_task_xmit -function \ -function iscsi_iser_cleanup_task -function iscsi_iser_check_protection -function \ -function iscsi_iser_conn_create -function iscsi_iser_conn_bind -function \ -function iscsi_iser_conn_start -function iscsi_iser_conn_stop -function \ -function iscsi_iser_session_destroy -function iscsi_iser_session_create -function \ -function iscsi_iser_set_param -function iscsi_iser_ep_connect -function iscsi_iser_ep_poll -function \ -function iscsi_iser_ep_disconnect ./drivers/infiniband/ulp/iser/iscsi_iser.c
+./diff-doc -rst -enable-lineno -function is_kfence_address -function kfence_shutdown_cache -function kfence_alloc -function kfence_free -function __kfence_free -function kfence_ksize -function kfence_object_start -function kfence_handle_page_fault ./include/linux/kfence.h
+./diff-doc -rst -enable-lineno -function kernel_hwtstamp_config ./include/linux/net_tstamp.h
+./diff-doc -rst -enable-lineno -function 'Key handling basics' ./net/mac80211/key.c
+./diff-doc -rst -enable-lineno -function kfree_const -function kvmalloc_node -function kvfree ./mm/util.c
+./diff-doc -rst -enable-lineno -function klp_patch -function klp_object -function klp_func -function klp_callbacks -function klp_state ./include/linux/livepatch.h
+./diff-doc -rst -enable-lineno -function 'kms locking' ./drivers/gpu/drm/drm_modeset_lock.c
+./diff-doc -rst -enable-lineno -function kpp_request_alloc -function kpp_request_free -function kpp_request_set_callback -function kpp_request_set_input -function kpp_request_set_output ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function kpp_request -function crypto_kpp -function kpp_alg -function kpp_secret ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function kstrdup -function kstrdup_const -function kstrndup -function kmemdup -function kmemdup_nul -function memdup_user -function vmemdup_user -function strndup_user -function memdup_user_nul ./mm/util.c
+./diff-doc -rst -enable-lineno -function kstrtol -function kstrtoul ./include/linux/kstrtox.h
+./diff-doc -rst -enable-lineno -function landlock_ruleset_attr ./include/uapi/linux/landlock.h
+./diff-doc -rst -enable-lineno -function landlock_rule_type -function landlock_path_beneath_attr -function landlock_net_port_attr ./include/uapi/linux/landlock.h
+./diff-doc -rst -enable-lineno -function lirc_scancode -function rc_proto ./include/uapi/linux/lirc.h
+./diff-doc -rst -enable-lineno -function 'locking convention' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function Locking ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function 'Lockless queue stopping / waking helpers.' ./include/net/netdev_queues.h
+./diff-doc -rst -enable-lineno -function 'Logical Rings, Logical Ring Contexts and Execlists' ./drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+./diff-doc -rst -enable-lineno -function 'LPE Audio integration for HDMI or DP playback' ./drivers/gpu/drm/i915/display/intel_lpe_audio.c
+./diff-doc -rst -enable-lineno -function 'lru scan roster' ./drivers/gpu/drm/drm_mm.c
+./diff-doc -rst -enable-lineno -function 'mac80211 workqueue' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'managed resources' ./drivers/gpu/drm/drm_managed.c
+./diff-doc -rst -enable-lineno -function 'Manual switching and manual power control' ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function manufacturer ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function 'Map layer' ./drivers/gpu/drm/xe/xe_map.h
+./diff-doc -rst -enable-lineno -function 'master and authentication' ./drivers/gpu/drm/drm_auth.c
+./diff-doc -rst -enable-lineno -function mctrl_gpio_init -function mctrl_gpio_free -function mctrl_gpio_to_gpiod -function mctrl_gpio_set -function mctrl_gpio_get -function mctrl_gpio_enable_ms -function mctrl_gpio_disable_ms ./drivers/tty/serial/serial_mctrl_gpio.c
+./diff-doc -rst -enable-lineno -function mdelay ./include/linux/delay.h
+./diff-doc -rst -enable-lineno -function 'MEI_HDCP Client Driver' ./drivers/misc/mei/hdcp/mei_hdcp.c
+./diff-doc -rst -enable-lineno -function memalloc_nofs_save -function memalloc_nofs_restore ./include/linux/sched/mm.h
+./diff-doc -rst -enable-lineno -function memalloc_noio_save -function memalloc_noio_restore ./include/linux/sched/mm.h
+./diff-doc -rst -enable-lineno -function 'memblock overview' ./mm/memblock.c
+./diff-doc -rst -enable-lineno -function mem_busy_percent ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function mem_info_gtt_total ./drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_gtt_used ./drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vis_vram_total ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vis_vram_used ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vram_total ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vram_used ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function 'memory domains' ./include/uapi/drm/amdgpu_drm.h
+./diff-doc -rst -enable-lineno -function 'Message Digest Algorithm Definitions' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function 'Migrate Layer' ./drivers/gpu/drm/xe/xe_migrate_doc.h
+./diff-doc -rst -enable-lineno -function mm_slot -function ksm_scan -function stable_node -function rmap_item ./mm/ksm.c
+./diff-doc -rst -enable-lineno -function 'MMU Notifier' ./drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+./diff-doc -rst -enable-lineno -function 'module debugging statistics overview' ./kernel/module/stats.c
+./diff-doc -rst -enable-lineno -function 'module statistics debugfs counters' ./kernel/module/stats.c
+./diff-doc -rst -enable-lineno -function mpcc_alpha_blend_mode ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -function mpcc_blnd_cfg ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -function msleep -function msleep_interruptible ./kernel/time/sleep_timeout.c
+./diff-doc -rst -enable-lineno -function 'Multi-tile Design' ./drivers/gpu/drm/xe/xe_tile.c
+./diff-doc -rst -enable-lineno -function nbcon_state -function nbcon_prio -function nbcon_context -function nbcon_write_context ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function net_bridge_vlan ./net/bridge/br_private.h
+./diff-doc -rst -enable-lineno -function of_fpga_bridge_get_to_list ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function of_fpga_mgr_get ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function of_gen_pool_get ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function of_reset_simple_xlate -function reset_controller_register -function reset_controller_unregister -function devm_reset_controller_register -function reset_controller_add_lookup ./drivers/reset/core.c
+./diff-doc -rst -enable-lineno -function operators ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function 'output probing helper overview' ./drivers/gpu/drm/drm_probe_helper.c
+./diff-doc -rst -enable-lineno -function 'overview and lifetime rules' ./drivers/gpu/drm/drm_prime.c
+./diff-doc -rst -enable-lineno -function overview ./arch/x86/kernel/cpu/intel_epb.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/base/component.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/dma-buf/dma-buf-sysfs-stats.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/display/drm_bridge_connector.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_atomic_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_atomic_uapi.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_blend.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_client.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_color_mgmt.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_crtc.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_crtc_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_dumb_buffers.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_encoder.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_exec.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_framebuffer.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_atomic_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_framebuffer_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_shmem_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_ttm_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_vram_helper.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_mipi_dbi.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_mm.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_of.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_panic.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_plane_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_privacy_screen.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_property.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_self_refresh_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_simple_kms_helper.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_syncobj.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_sysfs.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_writeback.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/nouveau/nouveau_exec.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/scheduler/sched_main.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/video/aperture.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/video/backlight/backlight.c
+./diff-doc -rst -enable-lineno -function overview ./include/drm/drm_modeset_helper_vtables.h
+./diff-doc -rst -enable-lineno -function overview ./include/drm/drm_module.h
+./diff-doc -rst -enable-lineno -function overview ./include/linux/iosys-map.h
+./diff-doc -rst -enable-lineno -function overview ./include/uapi/drm/drm_fourcc.h
+./diff-doc -rst -enable-lineno -function overview ./include/uapi/drm/drm_mode.h
+./diff-doc -rst -enable-lineno -function Overview ./mm/ksm.c
+./diff-doc -rst -enable-lineno -function 'Packet alignment' ./net/mac80211/rx.c
+./diff-doc -rst -enable-lineno -function 'Page mobility and placement hints' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function 'page_pool allocator' ./include/net/page_pool/helpers.h
+./diff-doc -rst -enable-lineno -function page_pool_create ./net/core/page_pool.c
+./diff-doc -rst -enable-lineno -function page_pool_put_page_bulk -function page_pool_get_stats ./net/core/page_pool.c
+./diff-doc -rst -enable-lineno -function page_pool_put_page -function page_pool_put_full_page -function page_pool_recycle_direct -function page_pool_free_va -function page_pool_dev_alloc_pages -function page_pool_dev_alloc_frag -function page_pool_dev_alloc -function page_pool_dev_alloc_va -function page_pool_get_dma_addr -function page_pool_get_dma_dir ./include/net/page_pool/helpers.h
+./diff-doc -rst -enable-lineno -function 'Pagetable building' ./drivers/gpu/drm/xe/xe_pt.c
+./diff-doc -rst -enable-lineno -function 'Panel Self Refresh (PSR/SRD)' ./drivers/gpu/drm/i915/display/intel_psr.c
+./diff-doc -rst -enable-lineno -function pci_device_id ./include/linux/mod_devicetable.h
+./diff-doc -rst -enable-lineno -function pci_driver ./include/linux/pci.h
+./diff-doc -rst -enable-lineno -function pcie_bw ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pcie_replay_count ./drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+./diff-doc -rst -enable-lineno -function PCODE ./drivers/gpu/drm/xe/xe_pcode.c
+./diff-doc -rst -enable-lineno -function pm_policy ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Power control' ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function power_dpm_force_performance_level ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function power_dpm_state ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Powersave support' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_BO interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_CONTEXT and DESTROY_CONTEXT interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_FREE_LIST and DESTROY_FREE_LIST interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL DEV_QUERY interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL GET_BO_MMAP_OFFSET interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL SUBMIT_JOBS interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL VM_MAP and VM_UNMAP interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR (Series 6 and later) and IMG Graphics Driver' ./drivers/gpu/drm/imagination/pvr_drv.c
+./diff-doc -rst -enable-lineno -function 'PowerVR UAPI' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk pp_dpm_pcie' ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pp_od_clk_voltage ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pp_power_profile_mode ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pp_table ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'PRIME Buffer Sharing' ./drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+./diff-doc -rst -enable-lineno -function 'PRIME Helpers' ./drivers/gpu/drm/drm_prime.c
+./diff-doc -rst -enable-lineno -function print ./include/drm/drm_print.h
+./diff-doc -rst -enable-lineno -function printk -function pr_emerg -function pr_alert -function pr_crit -function pr_err -function pr_warn -function pr_notice -function pr_info -function pr_fmt -function pr_debug -function pr_devel -function pr_cont ./include/linux/printk.h
+./diff-doc -rst -enable-lineno -function probe_type -function device_driver ./include/linux/device/driver.h
+./diff-doc -rst -enable-lineno -function product_name ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function product_number ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function PURPOSE ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function PVR_IOCTL ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function PVR_STATIC_ASSERT_64BIT_ALIGNED -function PVR_IOCTL_UNION_PADDING_CHECK -function pvr_ioctl_union_padding_check ./drivers/gpu/drm/imagination/pvr_device.h
+./diff-doc -rst -enable-lineno -function PXP ./drivers/gpu/drm/i915/pxp/intel_pxp.c
+./diff-doc -rst -enable-lineno -function 'Random number generator API' ./include/crypto/rng.h
+./diff-doc -rst -enable-lineno -function 'Readahead Overview' ./mm/readahead.c
+./diff-doc -rst -enable-lineno -function read_properties_unlocked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'Reclaim modifiers' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function 'rect utils' ./include/drm/drm_rect.h
+./diff-doc -rst -enable-lineno -function register_hpd_handlers -function dm_crtc_high_irq -function dm_pflip_high_irq ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function 'Register Table Processing' ./drivers/gpu/drm/xe/xe_rtp.c
+./diff-doc -rst -enable-lineno -function 'Regulatory enforcement infrastructure' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function regulatory_hint -function wiphy_apply_custom_regulatory -function freq_reg_info ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'Render command list generation' ./drivers/gpu/drm/vc4/vc4_render_cl.c
+./diff-doc -rst -enable-lineno -function request_firmware_direct ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function request_firmware ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function request_firmware_into_buf ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function request_firmware_nowait ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function 'Reservation Object Overview' ./drivers/dma-buf/dma-resv.c
+./diff-doc -rst -enable-lineno -function reset_control_reset -function reset_control_assert -function reset_control_deassert -function reset_control_status -function reset_control_acquire -function reset_control_release -function reset_control_rearm -function reset_control_put -function of_reset_control_get_count -function of_reset_control_array_get -function devm_reset_control_array_get -function reset_control_get_count ./drivers/reset/core.c
+./diff-doc -rst -enable-lineno -function 'RFkill integration' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'Ring Design' ./include/uapi/linux/target_core_user.h
+./diff-doc -rst -enable-lineno -function riscv_set_icache_flush_ctx ./arch/riscv/mm/cacheflush.c
+./diff-doc -rst -enable-lineno -function rng_alg ./include/crypto/rng.h
+./diff-doc -rst -enable-lineno -function rtnl_link_stats64 ./include/uapi/linux/if_link.h
+./diff-doc -rst -enable-lineno -function 'runtime pm' ./drivers/gpu/drm/i915/intel_runtime_pm.c
+./diff-doc -rst -enable-lineno -function 'RX A-MPDU aggregation' ./net/mac80211/agg-rx.c
+./diff-doc -rst -enable-lineno -function 'Scanning and BSS list handling' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'scdc helpers' ./drivers/gpu/drm/display/drm_scdc_helper.c
+./diff-doc -rst -enable-lineno -function 'scope-based cleanup helpers' ./include/linux/cleanup.h
+./diff-doc -rst -enable-lineno -function serial_number ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function serial_rs485 -function uart_get_rs485_mode ./include/uapi/linux/serial.h
+./diff-doc -rst -enable-lineno -function set_key_cmd -function ieee80211_key_conf -function ieee80211_key_flags -function ieee80211_get_tkip_p1k -function ieee80211_get_tkip_p1k_iv -function ieee80211_get_tkip_p2k ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function sgx_ioc_enclave_create -function sgx_ioc_enclave_add_pages -function sgx_ioc_enclave_init -function sgx_ioc_enclave_provision ./arch/x86/kernel/cpu/sgx/ioctl.c
+./diff-doc -rst -enable-lineno -function sgx_ioc_enclave_restrict_permissions -function sgx_ioc_enclave_modify_types -function sgx_ioc_enclave_remove_pages ./arch/x86/kernel/cpu/sgx/ioctl.c
+./diff-doc -rst -enable-lineno -function 'Shader validator for VC4.' ./drivers/gpu/drm/vc4/vc4_validate_shaders.c
+./diff-doc -rst -enable-lineno -function sig_alg ./include/crypto/sig.h
+./diff-doc -rst -enable-lineno -function 'Single Block Cipher API' ./include/crypto/internal/cipher.h
+./diff-doc -rst -enable-lineno -function 'skb checksums' ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -function smartshift_apu_power ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function smartshift_bias ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function smartshift_dgpu_power ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_bclk_ratio ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_clkdiv ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_pll ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_sysclk ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function 'Spatial multiplexing power save' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'special care dsi' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function spi_register_board_info ./drivers/spi/spi.c
+./diff-doc -rst -enable-lineno -function 'Split and Merge' ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function ssleep -function fsleep ./include/linux/delay.h
+./diff-doc -rst -enable-lineno -function sta_ampdu_mlme -function tid_ampdu_tx -function tid_ampdu_rx ./net/mac80211/sta_info.h
+./diff-doc -rst -enable-lineno -function sta_info -function ieee80211_sta_info_flags ./net/mac80211/sta_info.h
+./diff-doc -rst -enable-lineno -function 'STA information lifetime rules' ./net/mac80211/sta_info.c
+./diff-doc -rst -enable-lineno -function 'standard connector properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'standard CRTC properties' ./drivers/gpu/drm/drm_crtc.c
+./diff-doc -rst -enable-lineno -function 'standard plane properties' ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function start_tty -function stop_tty ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'ST-Ericsson MCDE Driver' ./drivers/gpu/drm/mcde/mcde_drv.c
+./diff-doc -rst -enable-lineno -function stratix10_svc_cb_data ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_client ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_client_msg ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_command_code ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_command_config_type ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function struct -function dcp_blob_fmt ./security/keys/trusted-keys/trusted_dcp.c
+./diff-doc -rst -enable-lineno -function struct -function page_pool_params ./include/net/page_pool/types.h
+./diff-doc -rst -enable-lineno -function struct -function page_pool_recycle_stats -function struct -function page_pool_alloc_stats -function struct -function page_pool_stats ./include/net/page_pool/types.h
+./diff-doc -rst -enable-lineno -function struct -function virtqueue ./include/linux/virtio.h
+./diff-doc -rst -enable-lineno -function struct -function vring_desc ./include/uapi/linux/virtio_ring.h
+./diff-doc -rst -enable-lineno -function 'Supported input formats and encodings' ./include/drm/bridge/dw_hdmi.h
+./diff-doc -rst -enable-lineno -function 'Symmetric Key Cipher API' ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function 'Symmetric Key Cipher Request Handle' ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function 'Synchronous Message Digest API' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function sys_landlock_add_rule ./security/landlock/syscalls.c
+./diff-doc -rst -enable-lineno -function sys_landlock_create_ruleset ./security/landlock/syscalls.c
+./diff-doc -rst -enable-lineno -function sys_landlock_restrict_self ./security/landlock/syscalls.c
+./diff-doc -rst -enable-lineno -function sys_lsm_get_self_attr ./security/lsm_syscalls.c
+./diff-doc -rst -enable-lineno -function sys_lsm_list_modules ./security/lsm_syscalls.c
+./diff-doc -rst -enable-lineno -function sys_lsm_set_self_attr ./security/lsm_syscalls.c
+./diff-doc -rst -enable-lineno -function teo-description ./drivers/cpuidle/governors/teo.c
+./diff-doc -rst -enable-lineno -function 'Test mode' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function textsearch_find -function textsearch_next -function \ -function textsearch_get_pattern -function textsearch_get_pattern_len ./include/linux/textsearch.h
+./diff-doc -rst -enable-lineno -function 'The i915 register macro definition style guide' ./drivers/gpu/drm/i915/i915_reg.h
+./diff-doc -rst -enable-lineno -function TH_LOG -function TEST -function TEST_SIGNAL -function FIXTURE -function FIXTURE_DATA -function FIXTURE_SETUP -function FIXTURE_TEARDOWN -function TEST_F -function TEST_HARNESS_MAIN -function FIXTURE_VARIANT -function FIXTURE_VARIANT_ADD ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function 'Tile group' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'tiling swizzling details' ./drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+./diff-doc -rst -enable-lineno -function ts_intro ./lib/textsearch.c
+./diff-doc -rst -enable-lineno -function TTM ./drivers/gpu/drm/ttm/ttm_module.c
+./diff-doc -rst -enable-lineno -function __tty_alloc_driver -function tty_driver_kref_put ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_buffer_lock_exclusive -function tty_buffer_unlock_exclusive ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -function tty_buffer_space_avail -function tty_buffer_set_limit ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -function tty_do_resize ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'TTY Driver Flags' ./include/linux/tty_driver.h
+./diff-doc -rst -enable-lineno -function tty_driver ./include/linux/tty_driver.h
+./diff-doc -rst -enable-lineno -function tty_get_baud_rate ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_hangup -function tty_vhangup -function tty_hung_up_p ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_init_termios ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_insert_flip_string_fixed_flag -function tty_insert_flip_string_flags -function tty_insert_flip_char ./include/linux/tty_flip.h
+./diff-doc -rst -enable-lineno -function tty_kopen_exclusive -function tty_kopen_shared -function tty_kclose ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_kref_get ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_kref_put ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_ldisc_ops ./include/linux/tty_ldisc.h
+./diff-doc -rst -enable-lineno -function tty_ldisc_ref_wait -function tty_ldisc_ref -function tty_ldisc_deref ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -function tty_name ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_operations ./include/linux/tty_driver.h
+./diff-doc -rst -enable-lineno -function tty_port_carrier_raised -function tty_port_raise_dtr_rts -function tty_port_lower_dtr_rts ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port ./include/linux/tty_port.h
+./diff-doc -rst -enable-lineno -function tty_port_init -function tty_port_destroy -function tty_port_get -function tty_port_put ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_install -function tty_port_open -function tty_port_block_til_ready -function tty_port_close -function tty_port_close_start -function tty_port_close_end -function tty_port_hangup -function tty_port_shutdown ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_link_device -function tty_port_register_device -function tty_port_register_device_attr ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_operations ./include/linux/tty_port.h
+./diff-doc -rst -enable-lineno -function tty_port_tty_get -function tty_port_tty_set ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_tty_hangup -function tty_port_tty_wakeup ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_prepare_flip_string -function tty_flip_buffer_push -function tty_ldisc_receive_buf ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -function tty_put_char ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_register_device -function tty_register_device_attr -function tty_unregister_device ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_register_driver -function tty_unregister_driver ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_register_ldisc -function tty_unregister_ldisc ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -function tty_release_struct -function tty_dev_name_to_number -function tty_get_icount ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_set_ldisc -function tty_ldisc_flush ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -function tty_standard_install ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'TTY Struct Flags' ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_struct ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_wakeup ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'TX A-MPDU aggregation' ./net/mac80211/agg-tx.c
+./diff-doc -rst -enable-lineno -function typec_altmode_driver -function typec_altmode_ops ./include/linux/usb/typec_altmode.h
+./diff-doc -rst -enable-lineno -function typec_altmode_enter -function typec_altmode_exit -function typec_altmode_attention -function typec_altmode_vdm -function typec_altmode_notify ./drivers/usb/typec/bus.c
+./diff-doc -rst -enable-lineno -function typec_altmode_get_plug -function typec_altmode_put_plug ./drivers/usb/typec/bus.c
+./diff-doc -rst -enable-lineno -function typec_altmode_register_driver -function typec_altmode_unregister_driver ./include/linux/usb/typec_altmode.h
+./diff-doc -rst -enable-lineno -function typec_altmode_update_active ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_cable_set_identity ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_match_altmode ./drivers/usb/typec/bus.c
+./diff-doc -rst -enable-lineno -function typec_partner_register_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_partner_set_identity ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_plug_register_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_port_register_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_register_cable -function typec_unregister_cable -function typec_register_plug -function typec_unregister_plug ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_register_partner -function typec_unregister_partner ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_register_port -function typec_unregister_port ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_set_data_role -function typec_set_pwr_role -function typec_set_vconn_role -function typec_set_pwr_opmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_set_orientation -function typec_set_mode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_switch_register -function typec_switch_unregister -function typec_mux_register -function typec_mux_unregister ./drivers/usb/typec/mux.c
+./diff-doc -rst -enable-lineno -function typec_unregister_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function UAPI ./include/uapi/linux/cxl_mem.h
+./diff-doc -rst -enable-lineno -function uart_ops ./include/linux/serial_core.h
+./diff-doc -rst -enable-lineno -function uart_port_tx_limited -function uart_port_tx ./include/linux/serial_core.h
+./diff-doc -rst -enable-lineno -function uart_update_timeout -function uart_get_baud_rate -function uart_get_divisor -function uart_match_port -function uart_write_wakeup -function uart_register_driver -function uart_unregister_driver -function uart_suspend_port -function uart_resume_port -function uart_add_one_port -function uart_remove_one_port -function uart_console_write -function uart_parse_earlycon -function uart_parse_options -function uart_set_options -function uart_get_lsr_info -function uart_handle_dcd_change -function uart_handle_cts_change -function uart_try_toggle_sysrq -function uart_get_console ./drivers/tty/serial/serial_core.c
+./diff-doc -rst -enable-lineno -function udelay -function ndelay ./include/asm-generic/delay.h
+./diff-doc -rst -enable-lineno -function unique_id ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function USAGE ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function usb_dfu_functional_descriptor ./include/uapi/linux/usb/functionfs.h
+./diff-doc -rst -enable-lineno -function 'Useful GFP flag combinations' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function 'User command execution' ./drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+./diff-doc -rst -enable-lineno -function 'Userspace I/O' ./drivers/target/target_core_user.c
+./diff-doc -rst -enable-lineno -function usleep_range -function usleep_range_idle ./include/linux/delay.h
+./diff-doc -rst -enable-lineno -function usleep_range_state ./kernel/time/sleep_timeout.c
+./diff-doc -rst -enable-lineno -function 'Utility functions' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'V3D GEM BO management support' ./drivers/gpu/drm/v3d/v3d_bo.c
+./diff-doc -rst -enable-lineno -function 'Variable refresh properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'vblank handling' ./drivers/gpu/drm/drm_vblank.c
+./diff-doc -rst -enable-lineno -function 'vblank works' ./drivers/gpu/drm/drm_vblank_work.c
+./diff-doc -rst -enable-lineno -function 'VC4 CRTC module' ./drivers/gpu/drm/vc4/vc4_crtc.c
+./diff-doc -rst -enable-lineno -function 'VC4 DPI module' ./drivers/gpu/drm/vc4/vc4_dpi.c
+./diff-doc -rst -enable-lineno -function 'VC4 DSI0/DSI1 module' ./drivers/gpu/drm/vc4/vc4_dsi.c
+./diff-doc -rst -enable-lineno -function 'VC4 Falcon HDMI module' ./drivers/gpu/drm/vc4/vc4_hdmi.c
+./diff-doc -rst -enable-lineno -function 'VC4 GEM BO management support' ./drivers/gpu/drm/vc4/vc4_bo.c
+./diff-doc -rst -enable-lineno -function 'VC4 HVS module.' ./drivers/gpu/drm/vc4/vc4_hvs.c
+./diff-doc -rst -enable-lineno -function 'VC4 plane module' ./drivers/gpu/drm/vc4/vc4_plane.c
+./diff-doc -rst -enable-lineno -function 'VC4 SDTV module' ./drivers/gpu/drm/vc4/vc4_vec.c
+./diff-doc -rst -enable-lineno -function vdso_sgx_enter_enclave_t ./arch/x86/include/uapi/asm/sgx.h
+./diff-doc -rst -enable-lineno -function vgasr_priv ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function vga_switcheroo_client ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function vga_switcheroo_client_id ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_client_ops ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_handler_flags_t ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_handler ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_state ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function 'Video BIOS Table (VBT)' ./drivers/gpu/drm/i915/display/intel_bios.c
+./diff-doc -rst -enable-lineno -function 'Video Clocks' ./drivers/gpu/drm/meson/meson_vclk.c
+./diff-doc -rst -enable-lineno -function 'Video Encoder' ./drivers/gpu/drm/meson/meson_venc.c
+./diff-doc -rst -enable-lineno -function 'Video Input Unit' ./drivers/gpu/drm/meson/meson_viu.c
+./diff-doc -rst -enable-lineno -function 'Video Post Processing' ./drivers/gpu/drm/meson/meson_vpp.c
+./diff-doc -rst -enable-lineno -function 'Video Processing Unit' ./drivers/gpu/drm/meson/meson_drv.c
+./diff-doc -rst -enable-lineno -function virtio_device_ready ./include/linux/virtio_config.h
+./diff-doc -rst -enable-lineno -function virtqueue_add_inbuf ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_add_outbuf ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_add_sgs ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_disable_cb ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_enable_cb ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_get_buf_ctx ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function 'Virtual Memory Address' ./drivers/gpu/drm/i915/i915_vma_types.h
+./diff-doc -rst -enable-lineno -function 'vkms (Virtual Kernel Modesetting)' ./drivers/gpu/drm/vkms/vkms_drv.c
+./diff-doc -rst -enable-lineno -function 'vma offset manager' ./drivers/gpu/drm/drm_vma_manager.c
+./diff-doc -rst -enable-lineno -function vring_interrupt ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function vtpmx_ioc_new_dev ./drivers/char/tpm/tpm_vtpm_proxy.c
+./diff-doc -rst -enable-lineno -function 'Watermark modifiers' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function wiphy_rfkill_set_hw_state -function wiphy_rfkill_start_polling -function wiphy_rfkill_stop_polling ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'WOPCM Layout' ./drivers/gpu/drm/i915/gt/intel_wopcm.c
+./diff-doc -rst -enable-lineno -function 'Write Once Protected Content Memory (WOPCM) Layout' ./drivers/gpu/drm/xe/xe_wopcm.c
+./diff-doc -rst -enable-lineno -function 'xdp redirect' ./net/core/filter.c
+./diff-doc -rst -enable-lineno -function 'Xe device coredump' ./drivers/gpu/drm/xe/xe_devcoredump.c
+./diff-doc -rst -enable-lineno -function 'Xe Power Management' ./drivers/gpu/drm/xe/xe_pm.c
+./diff-doc -rst -enable-lineno -function XSDFEC_ADD_LDPC_CODE_PARAMS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_CLEAR_STATS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_GET_CONFIG ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_GET_STATS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_GET_STATUS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_IS_ACTIVE ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_BYPASS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_DEFAULT_CONFIG ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_IRQ ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_ORDER ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_TURBO ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_START_DEV ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_STOP_DEV ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno ./include/linux/bio.h
+./diff-doc -rst -enable-lineno ./include/linux/blk-mq.h
+./diff-doc -rst -enable-lineno ./include/linux/bootconfig.h
+./diff-doc -rst -enable-lineno ./include/linux/buffer_head.h
+./diff-doc -rst -enable-lineno ./include/linux/connector.h
+./diff-doc -rst -enable-lineno ./include/linux/cpuhotplug.h
+./diff-doc -rst -enable-lineno ./include/linux/damon.h
+./diff-doc -rst -enable-lineno ./include/linux/devcoredump.h
+./diff-doc -rst -enable-lineno ./include/linux/devfreq-event.h
+./diff-doc -rst -enable-lineno ./include/linux/devfreq.h
+./diff-doc -rst -enable-lineno ./include/linux/edac.h
+./diff-doc -rst -enable-lineno ./include/linux/folio_queue.h
+./diff-doc -rst -enable-lineno ./include/linux/fprobe.h
+./diff-doc -rst -enable-lineno ./include/linux/fscache-cache.h
+./diff-doc -rst -enable-lineno ./include/linux/fscache.h
+./diff-doc -rst -enable-lineno ./include/linux/highmem.h
+./diff-doc -rst -enable-lineno ./include/linux/highmem-internal.h
+./diff-doc -rst -enable-lineno ./include/linux/host1x.h
+./diff-doc -rst -enable-lineno ./include/linux/hte.h
+./diff-doc -rst -enable-lineno ./include/linux/i2c-atr.h
+./diff-doc -rst -enable-lineno ./include/linux/i3c/device.h
+./diff-doc -rst -enable-lineno ./include/linux/i3c/master.h
+./diff-doc -rst -enable-lineno ./include/linux/iio/buffer.h
+./diff-doc -rst -enable-lineno ./include/linux/iio/iio.h
+./diff-doc -rst -enable-lineno ./include/linux/iio/trigger.h
+./diff-doc -rst -enable-lineno ./include/linux/interconnect-provider.h
+./diff-doc -rst -enable-lineno ./include/linux/int_log.h
+./diff-doc -rst -enable-lineno ./include/linux/irqdomain.h
+./diff-doc -rst -enable-lineno ./include/linux/kref.h
+./diff-doc -rst -enable-lineno ./include/linux/maple_tree.h
+./diff-doc -rst -enable-lineno ./include/linux/memblock.h
+./diff-doc -rst -enable-lineno ./include/linux/migrate.h
+./diff-doc -rst -enable-lineno ./include/linux/mm_inline.h
+./diff-doc -rst -enable-lineno ./include/linux/mmzone.h
+./diff-doc -rst -enable-lineno ./include/linux/netfs.h
+./diff-doc -rst -enable-lineno ./include/linux/padata.h
+./diff-doc -rst -enable-lineno ./include/linux/page-flags.h
+./diff-doc -rst -enable-lineno ./include/linux/page_ref.h
+./diff-doc -rst -enable-lineno ./include/linux/peci.h
+./diff-doc -rst -enable-lineno ./include/linux/pm.h
+./diff-doc -rst -enable-lineno ./include/linux/rculist_bl.h
+./diff-doc -rst -enable-lineno ./include/linux/rculist.h
+./diff-doc -rst -enable-lineno ./include/linux/rculist_nulls.h
+./diff-doc -rst -enable-lineno ./include/linux/rcupdate.h
+./diff-doc -rst -enable-lineno ./include/linux/rcupdate_trace.h
+./diff-doc -rst -enable-lineno ./include/linux/rcupdate_wait.h
+./diff-doc -rst -enable-lineno ./include/linux/rcuref.h
+./diff-doc -rst -enable-lineno ./include/linux/rcu_sync.h
+./diff-doc -rst -enable-lineno ./include/linux/rcutree.h
+./diff-doc -rst -enable-lineno ./include/linux/seqlock.h
+./diff-doc -rst -enable-lineno ./include/linux/srcu.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_acpi_notify.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_aggregator/controller.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_aggregator/device.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_aggregator/serial_hub.h
+./diff-doc -rst -enable-lineno ./include/linux/workqueue.h
+./diff-doc -rst -enable-lineno ./include/linux/xarray.h
+./diff-doc -rst -enable-lineno ./include/linux/xz.h
+./diff-doc -rst -enable-lineno ./include/media/cec-notifier.h
+./diff-doc -rst -enable-lineno ./include/media/cec-pin.h
+./diff-doc -rst -enable-lineno ./include/media/demux.h
+./diff-doc -rst -enable-lineno ./include/media/dmxdev.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_ca_en50221.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_demux.h
+./diff-doc -rst -enable-lineno ./include/media/dvbdev.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_frontend.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_net.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_ringbuffer.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_vb2.h
+./diff-doc -rst -enable-lineno ./include/media/media-dev-allocator.h
+./diff-doc -rst -enable-lineno ./include/media/media-device.h
+./diff-doc -rst -enable-lineno ./include/media/media-devnode.h
+./diff-doc -rst -enable-lineno ./include/media/media-entity.h
+./diff-doc -rst -enable-lineno ./include/media/media-request.h
+./diff-doc -rst -enable-lineno ./include/media/rc-core.h
+./diff-doc -rst -enable-lineno ./include/media/rc-map.h
+./diff-doc -rst -enable-lineno ./include/media/tuner.h
+./diff-doc -rst -enable-lineno ./include/media/tuner-types.h
+./diff-doc -rst -enable-lineno ./include/media/tveeprom.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-async.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-cci.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-common.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-ctrls.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-dev.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-device.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-dv-timings.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-event.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-fh.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-flash-led-class.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-fwnode.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-ioctl.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-mc.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-mediabus.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-mem2mem.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-rect.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-subdev.h
+./diff-doc -rst -enable-lineno ./include/media/videobuf2-core.h
+./diff-doc -rst -enable-lineno ./include/media/videobuf2-memops.h
+./diff-doc -rst -enable-lineno ./include/media/videobuf2-v4l2.h
+./diff-doc -rst -enable-lineno ./include/sound/compress_driver.h
+./diff-doc -rst -enable-lineno ./include/sound/control.h
+./diff-doc -rst -enable-lineno ./include/sound/core.h
+./diff-doc -rst -enable-lineno ./include/sound/dmaengine_pcm.h
+./diff-doc -rst -enable-lineno ./include/sound/jack.h
+./diff-doc -rst -enable-lineno ./include/sound/pcm.h
+./diff-doc -rst -enable-lineno ./include/sound/soc.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/i915_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/nouveau_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/panthor_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/xe_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dma-buf.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dpll.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/ca.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/dmx.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/frontend.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/net.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/iommufd.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/media/raspberrypi/pisp_be_config.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/netlink.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/rkisp1-config.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/surface_aggregator/cdev.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/surface_aggregator/dtx.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/vtpm_proxy.h
+./diff-doc -rst -enable-lineno ./include/uapi/sound/compress_offload.h
+./diff-doc -rst -enable-lineno ./include/uapi/sound/compress_params.h
+./diff-doc -rst -enable-lineno -internal ./arch/powerpc/sysdev/fsl_rio.c
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/asm/ccwdev.h
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/asm/ccwgroup.h
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/asm/cio.h
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/uapi/asm/cmb.h
+./diff-doc -rst -enable-lineno -internal ./arch/sh/boards/mach-dreamcast/rtc.c
+./diff-doc -rst -enable-lineno -internal ./arch/x86/include/asm/io.h
+./diff-doc -rst -enable-lineno -internal ./arch/x86/include/asm/uaccess.h
+./diff-doc -rst -enable-lineno -internal ./block/blk-core.c
+./diff-doc -rst -enable-lineno -internal ./block/blk-sysfs.c
+./diff-doc -rst -enable-lineno -internal ./block/genhd.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/ata_piix.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/libata-core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/libata-scsi.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/sata_sil.c
+./diff-doc -rst -enable-lineno -internal ./drivers/base/init.c
+./diff-doc -rst -enable-lineno -internal ./drivers/base/node.c
+./diff-doc -rst -enable-lineno -internal ./drivers/cxl/cxl.h
+./diff-doc -rst -enable-lineno -internal ./drivers/cxl/cxlmem.h
+./diff-doc -rst -enable-lineno -internal ./drivers/cxl/pci.c
+./diff-doc -rst -enable-lineno -internal ./drivers/firmware/edd.c
+./diff-doc -rst -enable-lineno -internal ./drivers/firmware/efi/libstub/mem.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/dc.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_atomic_plane.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_audio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_bios.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_cdclk.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dmc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_drrs.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dsb.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_fbc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_fifo_underrun.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_frontbuffer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_frontbuffer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_hotplug.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_lpe_audio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_psr.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_vbt_defs.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gem/i915_gem_tiling.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gt/intel_gt_mcr.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_cmd_parser.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_gem_evict.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_gem_gtt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_vgpu.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/intel_gvt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/intel_runtime_pm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/intel_uncore.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_devcoredump.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_ggtt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_ggtt_types.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_pcode.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_pm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_rtp.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_rtp.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_rtp_types.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_tile.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_wa.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/core/iwpm_util.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/iser/iscsi_iser.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/iser/iser_initiator.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/iser/iser_verbs.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/isert/ib_isert.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/srpt/ib_srpt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/srpt/ib_srpt.h
+./diff-doc -rst -enable-lineno -internal ./drivers/media/test-drivers/vimc/vimc-streamer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/mtd/nand/raw/nand_base.c
+./diff-doc -rst -enable-lineno -internal ./drivers/mtd/nand/raw/nand_bbt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd_base.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd.h
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd_pci.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd_platform.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/mdio_bus.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/phy.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/phy_device.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/sfp-bus.c
+./diff-doc -rst -enable-lineno -internal ./drivers/parport/daisy.c
+./diff-doc -rst -enable-lineno -internal ./drivers/pci/pci-sysfs.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/bus.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/controller.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/controller.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_msgb.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_packet_layer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_packet_layer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_parser.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_parser.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_request_layer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_request_layer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/pnp/core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/pnp/driver.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio-access.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio-driver.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio-scan.c
+./diff-doc -rst -enable-lineno -internal ./drivers/scsi/iscsi_tcp.c
+./diff-doc -rst -enable-lineno -internal ./drivers/scsi/scsi_netlink.c
+./diff-doc -rst -enable-lineno -internal ./drivers/slimbus/slimbus.h
+./diff-doc -rst -enable-lineno -internal ./drivers/staging/vme_user/vme.h
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/n_tty.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/vt/selection.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/vt/vt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/core/buffer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/core.h
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/gadget.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/gadget.h
+./diff-doc -rst -enable-lineno -internal ./drivers/video/fbdev/core/modedb.c
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1.c
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1_internal.h
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1_io.c
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1_netlink.h
+./diff-doc -rst -enable-lineno -internal ./fs/eventpoll.c
+./diff-doc -rst -enable-lineno -internal ./fs/jbd2/recovery.c
+./diff-doc -rst -enable-lineno -internal ./fs/locks.c
+./diff-doc -rst -enable-lineno -internal ./fs/proc/base.c
+./diff-doc -rst -enable-lineno -internal ./fs/pstore/zone.c
+./diff-doc -rst -enable-lineno -internal ./include/asm-generic/bitops/instrumented-atomic.h
+./diff-doc -rst -enable-lineno -internal ./include/asm-generic/bitops/instrumented-lock.h
+./diff-doc -rst -enable-lineno -internal ./include/asm-generic/bitops/instrumented-non-atomic.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp_dual_mode_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp_mst_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dsc.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_scdc_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_atomic.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_atomic_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_auth.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_bridge.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_client.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_color_mgmt.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_connector.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_crtc.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_damage_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_debugfs.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_device.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_drv.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_edid.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_eld.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_encoder.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_exec.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_fb_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_file.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_flip_work.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_fourcc.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_framebuffer.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_atomic_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_dma_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_shmem_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_vram_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gpuvm.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_ioctl.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_managed.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mipi_dbi.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mipi_dsi.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mm.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mode_config.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mode_object.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_modeset_helper_vtables.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_modeset_lock.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_modes.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_panel.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_panic.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_plane.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_prime.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_print.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_privacy_screen_driver.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_privacy_screen_machine.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_property.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_rect.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_simple_kms_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_syncobj.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_util.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_vblank.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_vblank_work.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_vma_manager.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_writeback.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/gpu_scheduler.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/intel/i915_component.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_caching.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_device.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_placement.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_pool.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_resource.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_tt.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/device.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/of.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/resource.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/static_stub.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/test.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/aperture.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/apple-gmux.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/atomic/atomic-arch-fallback.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/atomic/atomic-instrumented.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/atomic/atomic-long.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/backlight.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/clk.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/completion.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/component.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/counter.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dcache.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/debugobjects.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dim.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-buf.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence-array.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence-chain.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence-unwrap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-resv.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/energy_model.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/err.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/etherdevice.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/fortify-string.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/fs.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/gpio/driver.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/hdmi.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/hrtimer.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/hsi/hsi.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/i2c.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input/matrix_keypad.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input/mt.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input/sparse-keymap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/interrupt.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/iosys-map.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/irq.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/jbd2.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/jiffies.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/kfifo.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/kgdb.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/kthread.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/ktime.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/libps2.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/list.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/log2.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/math64.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mm.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mm_types.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/module.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mtd/rawnand.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mutex.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/netdevice.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/net.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of_device.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of_graph.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of_platform.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/overflow.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pagemap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/parport.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/phy.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/phylink.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pipe_fs_i.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/platform_device.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pstore_blk.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pstore_zone.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pwm.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pwrseq/provider.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/refcount.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/regulator/consumer.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/regulator/driver.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/regulator/machine.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/reset-controller.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/reset.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/rio_drv.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/rio.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/rslib.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/sched.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/sfp.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/slab.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/slimbus.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/spi/spi.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/string.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/sync_file.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/uio_driver.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/usb/composite.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/usb/gadget.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/usb.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/vgaarb.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/w1.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/wait.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/wmi.h
+./diff-doc -rst -enable-lineno -internal ./include/media/v4l2-jpeg.h
+./diff-doc -rst -enable-lineno -internal ./include/net/net_shaper.h
+./diff-doc -rst -enable-lineno -internal ./include/net/sock.h
+./diff-doc -rst -enable-lineno -internal ./include/scsi/scsi_device.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/block.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/irq.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/signal.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/workqueue.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/drm/drm.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/drm/drm_mode.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/cxl_mem.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/firewire-cdev.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/gen_stats.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/sync_file.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -internal ./ipc/util.c
+./diff-doc -rst -enable-lineno -internal ./kernel/acct.c
+./diff-doc -rst -enable-lineno -internal ./kernel/auditfilter.c
+./diff-doc -rst -enable-lineno -internal ./kernel/auditsc.c
+./diff-doc -rst -enable-lineno -internal ./kernel/exit.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/core.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/futex.h
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/pi.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/requeue.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/waitwake.c
+./diff-doc -rst -enable-lineno -internal ./kernel/irq/chip.c
+./diff-doc -rst -enable-lineno -internal ./kernel/relay.c
+./diff-doc -rst -enable-lineno -internal ./kernel/resource.c
+./diff-doc -rst -enable-lineno -internal ./kernel/sched/cpupri.c
+./diff-doc -rst -enable-lineno -internal ./kernel/sched/fair.c
+./diff-doc -rst -enable-lineno -internal ./kernel/signal.c
+./diff-doc -rst -enable-lineno -internal ./kernel/trace/blktrace.c
+./diff-doc -rst -enable-lineno -internal ./lib/bitmap.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/bcast.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/bearer.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/bearer.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/crypto.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/discover.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/link.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/msg.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_distr.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_distr.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_table.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_table.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/node.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/socket.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/subscr.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/subscr.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/topsrv.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/trace.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/udp_media.c
+./diff-doc -rst -enable-lineno -internal -nosymbol device_link_state ./include/linux/device.h
+./diff-doc -rst -enable-lineno -internal -nosymbol i915_perf_init -nosymbol i915_perf_fini -nosymbol i915_perf_register -nosymbol i915_perf_unregister -nosymbol i915_perf_open_ioctl -nosymbol i915_perf_release -nosymbol i915_perf_add_config_ioctl -nosymbol i915_perf_remove_config_ioctl -nosymbol read_properties_unlocked -nosymbol i915_perf_open_ioctl_locked -nosymbol i915_perf_destroy_locked -nosymbol i915_perf_read -nosymbol i915_perf_ioctl -nosymbol i915_perf_enable_locked -nosymbol i915_perf_disable_locked -nosymbol i915_perf_poll -nosymbol i915_perf_poll_locked -nosymbol i915_oa_stream_init -nosymbol i915_oa_read -nosymbol i915_oa_stream_enable -nosymbol i915_oa_stream_disable -nosymbol i915_oa_wait_unlocked -nosymbol i915_oa_poll_wait ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -internal -nosymbol kstrtol -nosymbol kstrtoul ./include/linux/kernel.h
+./diff-doc -rst -enable-lineno -internal -nosymbol mpcc_blnd_cfg -nosymbol mpcc_alpha_blend_mode ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -internal -nosymbol pci_device_id ./include/linux/mod_devicetable.h
+./diff-doc -rst -enable-lineno -internal ./security/security.c
+./diff-doc -rst -enable-lineno ./kernel/irq/handle.c
+./diff-doc -rst -enable-lineno ./kernel/irq/irqdesc.c
+./diff-doc -rst -enable-lineno ./kernel/irq/manage.c
+./diff-doc -rst -enable-lineno ./kernel/padata.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/srcutree.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/sync.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/tasks.h
+./diff-doc -rst -enable-lineno ./kernel/rcu/tree.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/tree_exp.h
+./diff-doc -rst -enable-lineno ./kernel/rcu/tree_stall.h
+./diff-doc -rst -enable-lineno ./kernel/rcu/update.c
+./diff-doc -rst -enable-lineno ./kernel/trace/fprobe.c
+./diff-doc -rst -enable-lineno ./kernel/workqueue.c
+./diff-doc -rst -enable-lineno ./lib/bootconfig.c
+./diff-doc -rst -enable-lineno ./lib/crc32.c
+./diff-doc -rst -enable-lineno ./lib/errseq.c
+./diff-doc -rst -enable-lineno ./lib/maple_tree.c
+./diff-doc -rst -enable-lineno ./lib/xarray.c
+./diff-doc -rst -enable-lineno ./mm/balloon_compaction.c
+./diff-doc -rst -enable-lineno ./mm/damon/core.c
+./diff-doc -rst -enable-lineno ./mm/highmem.c
+./diff-doc -rst -enable-lineno ./mm/huge_memory.c
+./diff-doc -rst -enable-lineno ./mm/hugetlb.c
+./diff-doc -rst -enable-lineno ./mm/io-mapping.c
+./diff-doc -rst -enable-lineno ./mm/kmemleak.c
+./diff-doc -rst -enable-lineno ./mm/maccess.c
+./diff-doc -rst -enable-lineno ./mm/mapping_dirty_helpers.c
+./diff-doc -rst -enable-lineno ./mm/memcontrol.c
+./diff-doc -rst -enable-lineno ./mm/memory_hotplug.c
+./diff-doc -rst -enable-lineno ./mm/mempolicy.c
+./diff-doc -rst -enable-lineno ./mm/memremap.c
+./diff-doc -rst -enable-lineno ./mm/migrate.c
+./diff-doc -rst -enable-lineno ./mm/migrate_device.c
+./diff-doc -rst -enable-lineno ./mm/mmap.c
+./diff-doc -rst -enable-lineno ./mm/mmu_notifier.c
+./diff-doc -rst -enable-lineno ./mm/page_alloc.c
+./diff-doc -rst -enable-lineno ./mm/percpu.c
+./diff-doc -rst -enable-lineno ./mm/rmap.c
+./diff-doc -rst -enable-lineno ./mm/shmem.c
+./diff-doc -rst -enable-lineno ./mm/swap.c
+./diff-doc -rst -enable-lineno ./mm/vmscan.c
+./diff-doc -rst -enable-lineno ./mm/zpool.c
+./diff-doc -rst -enable-lineno ./mm/zsmalloc.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/cdat.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/hdm.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/memdev.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/pci.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/port.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/region.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/misc/mei/hdcp/mei_hdcp.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./include/linux/generic-radix-tree.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./include/linux/idr.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./lib/idr.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./mm/memblock.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./security/landlock/fs.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./security/landlock/object.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./security/landlock/ruleset.h
+./diff-doc -rst -enable-lineno -nosymbol bus_type -nosymbol bus_notifier_event ./include/linux/device/bus.h
+./diff-doc -rst -enable-lineno -nosymbol class ./include/linux/device/class.h
+./diff-doc -rst -enable-lineno -nosymbol probe_type -nosymbol device_driver ./include/linux/device/driver.h
+./diff-doc -rst -enable-lineno ./sound/core/compress_offload.c
+./diff-doc -rst -enable-lineno ./sound/core/control.c
+./diff-doc -rst -enable-lineno ./sound/core/device.c
+./diff-doc -rst -enable-lineno ./sound/core/hwdep.c
+./diff-doc -rst -enable-lineno ./sound/core/info.c
+./diff-doc -rst -enable-lineno ./sound/core/init.c
+./diff-doc -rst -enable-lineno ./sound/core/isadma.c
+./diff-doc -rst -enable-lineno ./sound/core/jack.c
+./diff-doc -rst -enable-lineno ./sound/core/memalloc.c
+./diff-doc -rst -enable-lineno ./sound/core/memory.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_dmaengine.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_lib.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_memory.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_misc.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_native.c
+./diff-doc -rst -enable-lineno ./sound/core/rawmidi.c
+./diff-doc -rst -enable-lineno ./sound/core/sound.c
+./diff-doc -rst -enable-lineno ./sound/core/vmaster.c
+./diff-doc -rst -enable-lineno ./sound/drivers/mpu401/mpu401_uart.c
+./diff-doc -rst -enable-lineno ./sound/pci/ac97/ac97_codec.c
+./diff-doc -rst -enable-lineno ./sound/pci/ac97/ac97_pcm.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-component.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-compress.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-core.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-dapm.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-devres.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-generic-dmaengine-pcm.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-jack.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-ops.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-pcm.c
+./diff-doc -rst -enable-lineno ./sound/sound_core.c
diff --git a/diff-doc b/diff-doc
new file mode 100755
index 000000000000..3cce8bb25c04
--- /dev/null
+++ b/diff-doc
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+RST=
+MAN=
+ARGS=
+
+args=()
+
+while [ "$1" != "" ]; do
+ case $1 in
+ --rst|-rst)
+ RST=1
+ ;;
+ # For now, ignore line numbers
+ --enable-lineno|-enable-lineno)
+ ;;
+ --man|-man)
+ MAN=1
+ ;;
+ *)
+ args+=(${1@Q})
+ ;;
+ esac
+ shift
+done
+
+if [ -z "$args" ]; then
+ echo "Need a filename"
+ exit 1
+fi
+
+if [ -z $RST ]; then
+ if [ -z $MAN ]; then
+ RST=1
+ fi
+fi
+
+echo >org
+echo >new
+
+echo scripts/kernel-doc ${args[@]}
+
+if [ ! -z $MAN ]; then
+ eval ./scripts/kernel-doc.pl -man ${args[@]} >>org
+fi
+
+if [ ! -z $RST ]; then
+ eval ./scripts/kernel-doc.pl -rst ${args[@]} >>org
+fi
+
+if [ ! -z $MAN ]; then
+ eval ./scripts/kernel-doc.py -man ${args[@]} >>new
+fi
+
+if [ ! -z $RST ]; then
+ eval ./scripts/kernel-doc.py -rst ${args[@]} >>new
+fi
+
+diff -u -B org new
Thanks,
Mauro
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH v2 00/39] Implement kernel-doc in Python
2025-02-25 7:54 ` Mauro Carvalho Chehab
@ 2025-02-25 14:33 ` Jonathan Corbet
0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Corbet @ 2025-02-25 14:33 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Linux Doc Mailing List, linux-kernel, Arnd Bergmann, Bingbu Cao,
Greg Kroah-Hartman, Sakari Ailus, Takashi Sakamoto, Tianshu Qiu,
linux-arch, linux-hardening, linux-media, linux-staging,
linux1394-devel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> There's no need to rush things there, provided that people refrain
> touching the Perl version of kernel-doc. So yeah, postponing it to
> the next merge window makes sense to me. Perhaps we should announce
> somewhere that we're in the process of doing such replacement, asking
> people to wait for 6.15-rc before sending any changes to kernel-doc.
I have no problem with sending an announcement ... but I wouldn't worry
about a flood of changes to the Perl script creating more work. There's
not a lot of people willing to dive into that thing in the first
place...
Thanks,
jon
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
2025-02-25 7:38 ` Mauro Carvalho Chehab
@ 2025-02-25 20:10 ` Jonathan Corbet
2025-02-26 6:56 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Corbet @ 2025-02-25 20:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Linux Doc Mailing List, linux-hardening, linux-kernel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> Em Mon, 24 Feb 2025 16:38:58 -0700
> Jonathan Corbet <corbet@lwn.net> escreveu:
>
>> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
>>
>>
>> I also think you should give consideration to preserving the other
>> copyright notices in the Perl version. A language translation doesn't
>> remove existing copyrights...who knows how much creativity went into
>> some of those regexes?
>
> Makes sense, but the copyrights at kernel-doc.pl:
>
> ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
> ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
> ## Copyright (C) 2001 Simon Huggins ##
> ## Copyright (C) 2005-2012 Randy Dunlap ##
> ## Copyright (C) 2012 Dan Luedtke ##
> ## ##
> ## #define enhancements by Armin Kuster <akuster@mvista.com> ##
> ## Copyright (c) 2000 MontaVista Software, Inc. ##
> #
> # Copyright (C) 2022 Tomasz Warniełło (POD)
>
> Also doesn't preserve all copyrights from people that worked hard to
> maintain it all over those years.
Agreed ... and I'm not sure what we can do about that. But *removing*
existing copyright notices is a bit of a different story; that is
generally considered to be fairly bad form.
I don't have a problem with adding a longer credits area, I guess, if we
want to do that (though it's not normal for other source files). But
I'm not sure we need to.
Thanks,
jon
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
2025-02-25 20:10 ` Jonathan Corbet
@ 2025-02-26 6:56 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 50+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-26 6:56 UTC (permalink / raw)
To: Jonathan Corbet; +Cc: Linux Doc Mailing List, linux-hardening, linux-kernel
Em Tue, 25 Feb 2025 13:10:19 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
>
> > Em Mon, 24 Feb 2025 16:38:58 -0700
> > Jonathan Corbet <corbet@lwn.net> escreveu:
> >
> >> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> >>
> >>
> >> I also think you should give consideration to preserving the other
> >> copyright notices in the Perl version. A language translation doesn't
> >> remove existing copyrights...who knows how much creativity went into
> >> some of those regexes?
> >
> > Makes sense, but the copyrights at kernel-doc.pl:
> >
> > ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
> > ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
> > ## Copyright (C) 2001 Simon Huggins ##
> > ## Copyright (C) 2005-2012 Randy Dunlap ##
> > ## Copyright (C) 2012 Dan Luedtke ##
> > ## ##
> > ## #define enhancements by Armin Kuster <akuster@mvista.com> ##
> > ## Copyright (c) 2000 MontaVista Software, Inc. ##
> > #
> > # Copyright (C) 2022 Tomasz Warniełło (POD)
> >
> > Also doesn't preserve all copyrights from people that worked hard to
> > maintain it all over those years.
>
> Agreed ... and I'm not sure what we can do about that. But *removing*
> existing copyright notices is a bit of a different story; that is
> generally considered to be fairly bad form.
I'm with you: we shall not remove copyrights.
Yet, copyrights were originally developed for artwork (paintings, music
and such). So I guess we can borrow an analogy from there to try
understanding what a conversion like that would mean. At least for me,
it sounds like having two paintings of the same image: they both
reflect the same picture, but they have different brush strokes. They
also may have different painting styles that may look similar but are
different.
Using such analogy, let's say someone draws a new painting while looking
at a famous painting like Monalisa. Surely the painter should give credits
to Leonardo Da Vinci for his brilliant artwork, but, on the other hand,
he cannot and should not sign that his painting was authored by Leonardo
Da Vinci.
This is the same here: the Python code, while derivated from the
Perl version, doesn't have the same coding style ("brush strokes") nor
we can say that it were authored by the original writers. IMO, all we
can do is to give credits for the original authors and preserve GPLv2
license, which explicitly allows derivative work.
That's why I think we could give such credits with some preamble
note to distinguish it from the Python copyrights.
It could be something like:
# Converted from the kernel-doc script originally written in Perl
# under GPLv2, copyrighted since 1998 by the following authors:
Followed by a list of the contributors, or it could be mentioning the
original script and how people could browse to see the developers
who wrote/modified kernel-doc.
Feel free to suggest a better text if you think the above won't fit.
> I don't have a problem with adding a longer credits area, I guess, if we
> want to do that (though it's not normal for other source files). But
> I'm not sure we need to.
I have the same doubts, but on the other hand, looking at the
copyrights written on kernel-doc.pl since 2005 (git version), I can see
records for just 3 persons:
- Dan Luedtke: a single patch adding html5 support
1b40c1944db4 ("scripts/kernel-doc: added support for html5")
We didn't port html5 to Python - and html output was already removed
from kernel-doc a long time ago. Maybe there might have some small
pieces of his original work that could have been ported. I dunno.
- Tomasz Warniełło: basically, changes at the help/man part of the script
2b306ecaf57b scripts: kernel-doc: Refresh the copyright lines
258092a89085 scripts: kernel-doc: Drop obsolete comments
252b47da9fd9 scripts: kernel-doc: Replace the usage function
834cf6b9039e scripts: kernel-doc: Translate the "Other parameters" subsection of OPTIONS
c15de5a19a28 scripts: kernel-doc: Translate the "Output selection modifiers" subsection of OPTIONS
9c77f108f43a scripts: kernel-doc: Translate the "Output selection" subsection of OPTIONS
dd803b04b0a0 scripts: kernel-doc: Translate the "Output format selection modifier" subsection of OPTIONS
2875f7870821 scripts: kernel-doc: Translate the "Output format selection" subsection of OPTIONS
f1583922bf93 scripts: kernel-doc: Translate the DESCRIPTION section
43caf1a6823d scripts: kernel-doc: Relink argument parsing error handling to pod2usage
a5cdaea525c3 scripts: kernel-doc: Add the basic POD sections
Parts of the text used at the POD sections were preserved at the
Python version. I didn't check if the texts we're using were
authored by him.
- Randy Dunlap: 64 patches fixing things and improving the script
I'm pretty sure I ported lots of stuff from Randy to the Python
version.
At least for me, while it sounds right to give credits for the above
3 developers and also for Michael, Simon and Armin, who collaborated
and authored it before git time, it doesn't sound right to not mention
any but one of the several developers that have been maintaining it
since 2005. Now, the list, ordered by the number of patches is:
65 Randy Dunlap
57 Mauro Carvalho Chehab
32 Jani Nikula
20 Jonathan Corbet
11 Tomasz Warniełło
11 Johannes Berg
7 Kees Cook
6 Vegard Nossum
6 Aditya Srivastava
5 Paolo Bonzini
5 Martin Waitz
4 Matthew Wilcox
4 Daniel Vetter
3 Mike Rapoport
3 Danilo Cesar Lemes de Paula
3 Daniel Santos
3 Conchúr Navid
3 Borislav Petkov
3 Ben Hutchings
3 Andy Shevchenko
3 André Almeida
3 Akira Yokosawa
2 Yujie Liu
2 Yacine Belkadi
2 Sakari Ailus
2 Pavel Pisa
2 Pavan Kumar Linga
2 Markus Heiser
2 Jonathan Neuschäfer
2 Jason Baron
2 Jakub Kicinski
2 Ilya Dryomov
1 Will Deacon
1 valdis.kletnieks@vt.edu
1 Utkarsh Tripathi
1 Silvio Fricke
1 Rolf Eike Beer
1 Rich Walker
1 Richard Kennedy
1 Randy.Dunlap
1 Pierre-Louis Bossart
1 Peter Maydell
1 Nishanth Menon
1 Niklas Söderlund
1 Michal Wajdeczko
1 Masahiro Yamada
1 Mark Rutland
1 Lucas De Marchi
1 Linus Torvalds
1 Levin, Alexander (Sasha Levin)
1 Laurent Pinchart
1 Kamil Rytarowski
1 Jonathan Cameron
1 Johannes Weiner
1 Jérémy Bobbio
1 Jason Gunthorpe
1 Horia Geanta
1 Harvey Harrison
1 Greg Kroah-Hartman
1 Gabriel Krisman Bertazi
1 Donald Hunter
1 Dan Luedtke
1 Coco Li
1 Chen-Yu Tsai
1 Bart Van Assche
1 Anna-Maria Behnsen
1 Alexander Lobakin
1 Alexander A. Klimov
If you think the list is too long, one option would be to draw a line
(for instance picking developers with more than 2 patches or something
like that) and add an "and others" to not forget about the others.
We might analyze each individual contribution to see what was relevant
or not, ignoring for instance single-line authors that did changes like
this one:
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 28b761567815..f565536a2bef 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -2082 +2081,0 @@ sub dump_function($$) {
- $prototype =~ s/__devinit +//;
which almost certainly doesn't affect copyrights, which doesn't add any new
code to it, while preserving credits for single-patch authors that did
regex changes like this one:
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 3982d47048a7..724528f4b7d6 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1086 +1086 @@ sub dump_struct($$) {
- if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
+ if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
@@ -1101,0 +1102 @@ sub dump_struct($$) {
+ $members =~ s/\s*____cacheline_aligned/ /gos;
but for me it sounds a waste of our time to analyze all patches, and
we may risk of get things wrong, so I prefer to place the complete list.
Thanks,
Mauro
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 06/39] scripts/kernel-doc: drop dead code for Wcontents_before_sections
2025-02-24 9:08 ` [PATCH v2 06/39] scripts/kernel-doc: drop dead code for Wcontents_before_sections Mauro Carvalho Chehab
@ 2025-03-04 16:52 ` Jonathan Corbet
0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Corbet @ 2025-03-04 16:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Linux Doc Mailing List
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> There is a warning about contents before sections, which doesn't
> work, since in_doc_sect variable is always true at the point
> it is checked.
>
> Drop the dead code.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
I've applied patches 1-6, just to lighten the load slightly.
Thanks,
jon
^ permalink raw reply [flat|nested] 50+ messages in thread
end of thread, other threads:[~2025-03-04 16:52 UTC | newest]
Thread overview: 50+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-24 9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 01/39] include/asm-generic/io.h: fix kerneldoc markup Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 02/39] drivers: media: intel-ipu3.h: fix identation on a kernel-doc markup Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 03/39] drivers: firewire: firewire-cdev.h: " Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 04/39] docs: driver-api/infiniband.rst: fix Kerneldoc markup Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 05/39] scripts/kernel-doc: don't add not needed new lines Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 06/39] scripts/kernel-doc: drop dead code for Wcontents_before_sections Mauro Carvalho Chehab
2025-03-04 16:52 ` Jonathan Corbet
2025-02-24 9:08 ` [PATCH v2 07/39] scripts/kernel-doc: rename it to scripts/kernel-doc.pl Mauro Carvalho Chehab
2025-02-24 23:23 ` Jonathan Corbet
2025-02-25 6:26 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 08/39] scripts/kernel-doc: add a symlink to the Perl version of kernel-doc Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
2025-02-24 23:38 ` Jonathan Corbet
2025-02-25 7:38 ` Mauro Carvalho Chehab
2025-02-25 20:10 ` Jonathan Corbet
2025-02-26 6:56 ` Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 10/39] scripts/kernel-doc.py: output warnings the same way as kerneldoc Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 11/39] scripts/kernel-doc.py: better handle empty sections Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 12/39] scripts/kernel-doc.py: properly handle struct_group macros Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 13/39] scripts/kernel-doc.py: move regex methods to a separate file Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class " Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 15/39] scripts/kernel-doc.py: move KernelFiles " Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 16/39] scripts/kernel-doc.py: move output classes " Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 17/39] scripts/kernel-doc.py: convert message output to an interactor Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 18/39] scripts/kernel-doc.py: move file lists to the parser function Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 19/39] scripts/kernel-doc.py: implement support for -no-doc-sections Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 20/39] scripts/kernel-doc.py: fix line number output Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 21/39] scripts/kernel-doc.py: fix handling of doc output check Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 22/39] scripts/kernel-doc.py: properly handle out_section for ReST Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 23/39] scripts/kernel-doc.py: postpone warnings to the output plugin Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 24/39] docs: add a .pylintrc file with sys path for docs scripts Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 25/39] docs: sphinx: kerneldoc: verbose kernel-doc command if V=1 Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 26/39] docs: sphinx: kerneldoc: ignore "\" characters from options Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 27/39] docs: sphinx: kerneldoc: use kernel-doc.py script Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 28/39] scripts/kernel-doc.py: Set an output format for --none Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 29/39] scripts/kernel-doc.py: adjust some coding style issues Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 30/39] scripts/lib/kdoc/kdoc_parser.py: fix Python compat with < v3.13 Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 31/39] scripts/kernel-doc.py: move modulename to man class Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 32/39] scripts/kernel-doc.py: properly handle KBUILD_BUILD_TIMESTAMP Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 33/39] scripts/lib/kdoc/kdoc_parser.py: remove a python 3.9 dependency Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 34/39] scripts/kernel-doc.py: Properly handle Werror and exit codes Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 35/39] scripts/kernel-doc.py: some coding style cleanups Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 36/39] scripts/kernel-doc: switch to use kernel-doc.py Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 37/39] scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 38/39] scripts/kernel_doc.py: better handle exported symbols Mauro Carvalho Chehab
2025-02-24 9:08 ` [PATCH v2 39/39] docs: sphinx: kerneldoc: Use python class if available Mauro Carvalho Chehab
2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
2025-02-25 7:54 ` Mauro Carvalho Chehab
2025-02-25 14:33 ` Jonathan Corbet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).