Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/lib/python/kdoc/kdoc_output.py
122941 views
1
#!/usr/bin/env python3
2
# SPDX-License-Identifier: GPL-2.0
3
# Copyright(c) 2025: Mauro Carvalho Chehab <[email protected]>.
4
#
5
# pylint: disable=C0301,R0902,R0911,R0912,R0913,R0914,R0915,R0917
6
7
"""
8
Classes to implement output filters to print kernel-doc documentation.
9
10
The implementation uses a virtual base class ``OutputFormat``. It
11
contains dispatches to virtual methods, and some code to filter
12
out output messages.
13
14
The actual implementation is done on one separate class per each type
15
of output, e.g. ``RestFormat`` and ``ManFormat`` classes.
16
17
Currently, there are output classes for ReST and man/troff.
18
"""
19
20
import os
21
import re
22
from datetime import datetime
23
24
from kdoc.kdoc_parser import KernelDoc, type_param
25
from kdoc.kdoc_re import KernRe
26
27
28
function_pointer = KernRe(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
29
30
# match expressions used to find embedded type information
31
type_constant = KernRe(r"\b``([^\`]+)``\b", cache=False)
32
type_constant2 = KernRe(r"\%([-_*\w]+)", cache=False)
33
type_func = KernRe(r"(\w+)\(\)", cache=False)
34
type_param_ref = KernRe(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
35
36
# Special RST handling for func ptr params
37
type_fp_param = KernRe(r"\@(\w+)\(\)", cache=False)
38
39
# Special RST handling for structs with func ptr params
40
type_fp_param2 = KernRe(r"\@(\w+->\S+)\(\)", cache=False)
41
42
type_env = KernRe(r"(\$\w+)", cache=False)
43
type_enum = KernRe(r"\&(enum\s*([_\w]+))", cache=False)
44
type_struct = KernRe(r"\&(struct\s*([_\w]+))", cache=False)
45
type_typedef = KernRe(r"\&(typedef\s*([_\w]+))", cache=False)
46
type_union = KernRe(r"\&(union\s*([_\w]+))", cache=False)
47
type_member = KernRe(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
48
type_fallback = KernRe(r"\&([_\w]+)", cache=False)
49
type_member_func = type_member + KernRe(r"\(\)", cache=False)
50
51
52
class OutputFormat:
53
"""
54
Base class for OutputFormat. If used as-is, it means that only
55
warnings will be displayed.
56
"""
57
58
# output mode.
59
OUTPUT_ALL = 0 #: Output all symbols and doc sections.
60
OUTPUT_INCLUDE = 1 #: Output only specified symbols.
61
OUTPUT_EXPORTED = 2 #: Output exported symbols.
62
OUTPUT_INTERNAL = 3 #: Output non-exported symbols.
63
64
#: Highlights to be used in ReST format.
65
highlights = []
66
67
#: Blank line character.
68
blankline = ""
69
70
def __init__(self):
71
"""Declare internal vars and set mode to ``OUTPUT_ALL``."""
72
73
self.out_mode = self.OUTPUT_ALL
74
self.enable_lineno = None
75
self.nosymbol = {}
76
self.symbol = None
77
self.function_table = None
78
self.config = None
79
self.no_doc_sections = False
80
81
self.data = ""
82
83
def set_config(self, config):
84
"""
85
Setup global config variables used by both parser and output.
86
"""
87
88
self.config = config
89
90
def set_filter(self, export, internal, symbol, nosymbol, function_table,
91
enable_lineno, no_doc_sections):
92
"""
93
Initialize filter variables according to the requested mode.
94
95
Only one choice is valid between export, internal and symbol.
96
97
The nosymbol filter can be used on all modes.
98
"""
99
100
self.enable_lineno = enable_lineno
101
self.no_doc_sections = no_doc_sections
102
self.function_table = function_table
103
104
if symbol:
105
self.out_mode = self.OUTPUT_INCLUDE
106
elif export:
107
self.out_mode = self.OUTPUT_EXPORTED
108
elif internal:
109
self.out_mode = self.OUTPUT_INTERNAL
110
else:
111
self.out_mode = self.OUTPUT_ALL
112
113
if nosymbol:
114
self.nosymbol = set(nosymbol)
115
116
117
def highlight_block(self, block):
118
"""
119
Apply the RST highlights to a sub-block of text.
120
"""
121
122
for r, sub in self.highlights:
123
block = r.sub(sub, block)
124
125
return block
126
127
def out_warnings(self, args):
128
"""
129
Output warnings for identifiers that will be displayed.
130
"""
131
132
for log_msg in args.warnings:
133
self.config.warning(log_msg)
134
135
def check_doc(self, name, args):
136
"""Check if DOC should be output."""
137
138
if self.no_doc_sections:
139
return False
140
141
if name in self.nosymbol:
142
return False
143
144
if self.out_mode == self.OUTPUT_ALL:
145
self.out_warnings(args)
146
return True
147
148
if self.out_mode == self.OUTPUT_INCLUDE:
149
if name in self.function_table:
150
self.out_warnings(args)
151
return True
152
153
return False
154
155
def check_declaration(self, dtype, name, args):
156
"""
157
Checks if a declaration should be output or not based on the
158
filtering criteria.
159
"""
160
161
if name in self.nosymbol:
162
return False
163
164
if self.out_mode == self.OUTPUT_ALL:
165
self.out_warnings(args)
166
return True
167
168
if self.out_mode in [self.OUTPUT_INCLUDE, self.OUTPUT_EXPORTED]:
169
if name in self.function_table:
170
return True
171
172
if self.out_mode == self.OUTPUT_INTERNAL:
173
if dtype != "function":
174
self.out_warnings(args)
175
return True
176
177
if name not in self.function_table:
178
self.out_warnings(args)
179
return True
180
181
return False
182
183
def msg(self, fname, name, args):
184
"""
185
Handles a single entry from kernel-doc parser.
186
"""
187
188
self.data = ""
189
190
dtype = args.type
191
192
if dtype == "doc":
193
self.out_doc(fname, name, args)
194
return self.data
195
196
if not self.check_declaration(dtype, name, args):
197
return self.data
198
199
if dtype == "function":
200
self.out_function(fname, name, args)
201
return self.data
202
203
if dtype == "enum":
204
self.out_enum(fname, name, args)
205
return self.data
206
207
if dtype == "var":
208
self.out_var(fname, name, args)
209
return self.data
210
211
if dtype == "typedef":
212
self.out_typedef(fname, name, args)
213
return self.data
214
215
if dtype in ["struct", "union"]:
216
self.out_struct(fname, name, args)
217
return self.data
218
219
# Warn if some type requires an output logic
220
self.config.log.warning("doesn't know how to output '%s' block",
221
dtype)
222
223
return None
224
225
# Virtual methods to be overridden by inherited classes
226
# At the base class, those do nothing.
227
def set_symbols(self, symbols):
228
"""Get a list of all symbols from kernel_doc."""
229
230
def out_doc(self, fname, name, args):
231
"""Outputs a DOC block."""
232
233
def out_function(self, fname, name, args):
234
"""Outputs a function."""
235
236
def out_enum(self, fname, name, args):
237
"""Outputs an enum."""
238
239
def out_var(self, fname, name, args):
240
"""Outputs a variable."""
241
242
def out_typedef(self, fname, name, args):
243
"""Outputs a typedef."""
244
245
def out_struct(self, fname, name, args):
246
"""Outputs a struct."""
247
248
249
class RestFormat(OutputFormat):
250
"""Consts and functions used by ReST output."""
251
252
#: Highlights to be used in ReST format
253
highlights = [
254
(type_constant, r"``\1``"),
255
(type_constant2, r"``\1``"),
256
257
# Note: need to escape () to avoid func matching later
258
(type_member_func, r":c:type:`\1\2\3\\(\\) <\1>`"),
259
(type_member, r":c:type:`\1\2\3 <\1>`"),
260
(type_fp_param, r"**\1\\(\\)**"),
261
(type_fp_param2, r"**\1\\(\\)**"),
262
(type_func, r"\1()"),
263
(type_enum, r":c:type:`\1 <\2>`"),
264
(type_struct, r":c:type:`\1 <\2>`"),
265
(type_typedef, r":c:type:`\1 <\2>`"),
266
(type_union, r":c:type:`\1 <\2>`"),
267
268
# in rst this can refer to any type
269
(type_fallback, r":c:type:`\1`"),
270
(type_param_ref, r"**\1\2**")
271
]
272
273
blankline = "\n"
274
275
#: Sphinx literal block regex.
276
sphinx_literal = KernRe(r'^[^.].*::$', cache=False)
277
278
#: Sphinx code block regex.
279
sphinx_cblock = KernRe(r'^\.\.\ +code-block::', cache=False)
280
281
def __init__(self):
282
"""
283
Creates class variables.
284
285
Not really mandatory, but it is a good coding style and makes
286
pylint happy.
287
"""
288
289
super().__init__()
290
self.lineprefix = ""
291
292
def print_lineno(self, ln):
293
"""Outputs a line number."""
294
295
if self.enable_lineno and ln is not None:
296
ln += 1
297
self.data += f".. LINENO {ln}\n"
298
299
def output_highlight(self, args):
300
"""
301
Outputs a C symbol that may require being converted to ReST using
302
the self.highlights variable.
303
"""
304
305
input_text = args
306
output = ""
307
in_literal = False
308
litprefix = ""
309
block = ""
310
311
for line in input_text.strip("\n").split("\n"):
312
313
# If we're in a literal block, see if we should drop out of it.
314
# Otherwise, pass the line straight through unmunged.
315
if in_literal:
316
if line.strip(): # If the line is not blank
317
# If this is the first non-blank line in a literal block,
318
# figure out the proper indent.
319
if not litprefix:
320
r = KernRe(r'^(\s*)')
321
if r.match(line):
322
litprefix = '^' + r.group(1)
323
else:
324
litprefix = ""
325
326
output += line + "\n"
327
elif not KernRe(litprefix).match(line):
328
in_literal = False
329
else:
330
output += line + "\n"
331
else:
332
output += line + "\n"
333
334
# Not in a literal block (or just dropped out)
335
if not in_literal:
336
block += line + "\n"
337
if self.sphinx_literal.match(line) or self.sphinx_cblock.match(line):
338
in_literal = True
339
litprefix = ""
340
output += self.highlight_block(block)
341
block = ""
342
343
# Handle any remaining block
344
if block:
345
output += self.highlight_block(block)
346
347
# Print the output with the line prefix
348
for line in output.strip("\n").split("\n"):
349
self.data += self.lineprefix + line + "\n"
350
351
def out_section(self, args, out_docblock=False):
352
"""
353
Outputs a block section.
354
355
This could use some work; it's used to output the DOC: sections, and
356
starts by putting out the name of the doc section itself, but that
357
tends to duplicate a header already in the template file.
358
"""
359
for section, text in args.sections.items():
360
# Skip sections that are in the nosymbol_table
361
if section in self.nosymbol:
362
continue
363
364
if out_docblock:
365
if not self.out_mode == self.OUTPUT_INCLUDE:
366
self.data += f".. _{section}:\n\n"
367
self.data += f'{self.lineprefix}**{section}**\n\n'
368
else:
369
self.data += f'{self.lineprefix}**{section}**\n\n'
370
371
self.print_lineno(args.section_start_lines.get(section, 0))
372
self.output_highlight(text)
373
self.data += "\n"
374
self.data += "\n"
375
376
def out_doc(self, fname, name, args):
377
if not self.check_doc(name, args):
378
return
379
self.out_section(args, out_docblock=True)
380
381
def out_function(self, fname, name, args):
382
383
oldprefix = self.lineprefix
384
signature = ""
385
386
func_macro = args.get('func_macro', False)
387
if func_macro:
388
signature = name
389
else:
390
if args.get('functiontype'):
391
signature = args['functiontype'] + " "
392
signature += name + " ("
393
394
ln = args.declaration_start_line
395
count = 0
396
for parameter in args.parameterlist:
397
if count != 0:
398
signature += ", "
399
count += 1
400
dtype = args.parametertypes.get(parameter, "")
401
402
if function_pointer.search(dtype):
403
signature += function_pointer.group(1) + parameter + function_pointer.group(3)
404
else:
405
signature += dtype
406
407
if not func_macro:
408
signature += ")"
409
410
self.print_lineno(ln)
411
if args.get('typedef') or not args.get('functiontype'):
412
self.data += f".. c:macro:: {name}\n\n"
413
414
if args.get('typedef'):
415
self.data += " **Typedef**: "
416
self.lineprefix = ""
417
self.output_highlight(args.get('purpose', ""))
418
self.data += "\n\n**Syntax**\n\n"
419
self.data += f" ``{signature}``\n\n"
420
else:
421
self.data += f"``{signature}``\n\n"
422
else:
423
self.data += f".. c:function:: {signature}\n\n"
424
425
if not args.get('typedef'):
426
self.print_lineno(ln)
427
self.lineprefix = " "
428
self.output_highlight(args.get('purpose', ""))
429
self.data += "\n"
430
431
# Put descriptive text into a container (HTML <div>) to help set
432
# function prototypes apart
433
self.lineprefix = " "
434
435
if args.parameterlist:
436
self.data += ".. container:: kernelindent\n\n"
437
self.data += f"{self.lineprefix}**Parameters**\n\n"
438
439
for parameter in args.parameterlist:
440
parameter_name = KernRe(r'\[.*').sub('', parameter)
441
dtype = args.parametertypes.get(parameter, "")
442
443
if dtype:
444
self.data += f"{self.lineprefix}``{dtype}``\n"
445
else:
446
self.data += f"{self.lineprefix}``{parameter}``\n"
447
448
self.print_lineno(args.parameterdesc_start_lines.get(parameter_name, 0))
449
450
self.lineprefix = " "
451
if parameter_name in args.parameterdescs and \
452
args.parameterdescs[parameter_name] != KernelDoc.undescribed:
453
454
self.output_highlight(args.parameterdescs[parameter_name])
455
self.data += "\n"
456
else:
457
self.data += f"{self.lineprefix}*undescribed*\n\n"
458
self.lineprefix = " "
459
460
self.out_section(args)
461
self.lineprefix = oldprefix
462
463
def out_enum(self, fname, name, args):
464
465
oldprefix = self.lineprefix
466
ln = args.declaration_start_line
467
468
self.data += f"\n\n.. c:enum:: {name}\n\n"
469
470
self.print_lineno(ln)
471
self.lineprefix = " "
472
self.output_highlight(args.get('purpose', ''))
473
self.data += "\n"
474
475
self.data += ".. container:: kernelindent\n\n"
476
outer = self.lineprefix + " "
477
self.lineprefix = outer + " "
478
self.data += f"{outer}**Constants**\n\n"
479
480
for parameter in args.parameterlist:
481
self.data += f"{outer}``{parameter}``\n"
482
483
if args.parameterdescs.get(parameter, '') != KernelDoc.undescribed:
484
self.output_highlight(args.parameterdescs[parameter])
485
else:
486
self.data += f"{self.lineprefix}*undescribed*\n\n"
487
self.data += "\n"
488
489
self.lineprefix = oldprefix
490
self.out_section(args)
491
492
def out_var(self, fname, name, args):
493
oldprefix = self.lineprefix
494
ln = args.declaration_start_line
495
full_proto = args.other_stuff["full_proto"]
496
497
self.lineprefix = " "
498
499
self.data += f"\n\n.. c:macro:: {name}\n\n{self.lineprefix}``{full_proto}``\n\n"
500
501
self.print_lineno(ln)
502
self.output_highlight(args.get('purpose', ''))
503
self.data += "\n"
504
505
if args.other_stuff["default_val"]:
506
self.data += f'{self.lineprefix}**Initialization**\n\n'
507
self.output_highlight(f'default: ``{args.other_stuff["default_val"]}``')
508
509
self.out_section(args)
510
511
def out_typedef(self, fname, name, args):
512
513
oldprefix = self.lineprefix
514
ln = args.declaration_start_line
515
516
self.data += f"\n\n.. c:type:: {name}\n\n"
517
518
self.print_lineno(ln)
519
self.lineprefix = " "
520
521
self.output_highlight(args.get('purpose', ''))
522
523
self.data += "\n"
524
525
self.lineprefix = oldprefix
526
self.out_section(args)
527
528
def out_struct(self, fname, name, args):
529
530
purpose = args.get('purpose', "")
531
declaration = args.get('definition', "")
532
dtype = args.type
533
ln = args.declaration_start_line
534
535
self.data += f"\n\n.. c:{dtype}:: {name}\n\n"
536
537
self.print_lineno(ln)
538
539
oldprefix = self.lineprefix
540
self.lineprefix += " "
541
542
self.output_highlight(purpose)
543
self.data += "\n"
544
545
self.data += ".. container:: kernelindent\n\n"
546
self.data += f"{self.lineprefix}**Definition**::\n\n"
547
548
self.lineprefix = self.lineprefix + " "
549
550
declaration = declaration.replace("\t", self.lineprefix)
551
552
self.data += f"{self.lineprefix}{dtype} {name}" + ' {' + "\n"
553
self.data += f"{declaration}{self.lineprefix}" + "};\n\n"
554
555
self.lineprefix = " "
556
self.data += f"{self.lineprefix}**Members**\n\n"
557
for parameter in args.parameterlist:
558
if not parameter or parameter.startswith("#"):
559
continue
560
561
parameter_name = parameter.split("[", maxsplit=1)[0]
562
563
if args.parameterdescs.get(parameter_name) == KernelDoc.undescribed:
564
continue
565
566
self.print_lineno(args.parameterdesc_start_lines.get(parameter_name, 0))
567
568
self.data += f"{self.lineprefix}``{parameter}``\n"
569
570
self.lineprefix = " "
571
self.output_highlight(args.parameterdescs[parameter_name])
572
self.lineprefix = " "
573
574
self.data += "\n"
575
576
self.data += "\n"
577
578
self.lineprefix = oldprefix
579
self.out_section(args)
580
581
582
class ManFormat(OutputFormat):
583
"""Consts and functions used by man pages output."""
584
585
highlights = (
586
(type_constant, r"\1"),
587
(type_constant2, r"\1"),
588
(type_func, r"\\fB\1\\fP"),
589
(type_enum, r"\\fI\1\\fP"),
590
(type_struct, r"\\fI\1\\fP"),
591
(type_typedef, r"\\fI\1\\fP"),
592
(type_union, r"\\fI\1\\fP"),
593
(type_param, r"\\fI\1\\fP"),
594
(type_param_ref, r"\\fI\1\2\\fP"),
595
(type_member, r"\\fI\1\2\3\\fP"),
596
(type_fallback, r"\\fI\1\\fP")
597
)
598
blankline = ""
599
600
#: Allowed timestamp formats.
601
date_formats = [
602
"%a %b %d %H:%M:%S %Z %Y",
603
"%a %b %d %H:%M:%S %Y",
604
"%Y-%m-%d",
605
"%b %d %Y",
606
"%B %d %Y",
607
"%m %d %Y",
608
]
609
610
def __init__(self, modulename):
611
"""
612
Creates class variables.
613
614
Not really mandatory, but it is a good coding style and makes
615
pylint happy.
616
"""
617
618
super().__init__()
619
self.modulename = modulename
620
self.symbols = []
621
622
dt = None
623
tstamp = os.environ.get("KBUILD_BUILD_TIMESTAMP")
624
if tstamp:
625
for fmt in self.date_formats:
626
try:
627
dt = datetime.strptime(tstamp, fmt)
628
break
629
except ValueError:
630
pass
631
632
if not dt:
633
dt = datetime.now()
634
635
self.man_date = dt.strftime("%B %Y")
636
637
def arg_name(self, args, name):
638
"""
639
Return the name that will be used for the man page.
640
641
As we may have the same name on different namespaces,
642
prepend the data type for all types except functions and typedefs.
643
644
The doc section is special: it uses the modulename.
645
"""
646
647
dtype = args.type
648
649
if dtype == "doc":
650
return self.modulename
651
652
if dtype in ["function", "typedef"]:
653
return name
654
655
return f"{dtype} {name}"
656
657
def set_symbols(self, symbols):
658
"""
659
Get a list of all symbols from kernel_doc.
660
661
Man pages will uses it to add a SEE ALSO section with other
662
symbols at the same file.
663
"""
664
self.symbols = symbols
665
666
def out_tail(self, fname, name, args):
667
"""Adds a tail for all man pages."""
668
669
# SEE ALSO section
670
self.data += f'.SH "SEE ALSO"' + "\n.PP\n"
671
self.data += (f"Kernel file \\fB{args.fname}\\fR\n")
672
if len(self.symbols) >= 2:
673
cur_name = self.arg_name(args, name)
674
675
related = []
676
for arg in self.symbols:
677
out_name = self.arg_name(arg, arg.name)
678
679
if cur_name == out_name:
680
continue
681
682
related.append(f"\\fB{out_name}\\fR(9)")
683
684
self.data += ",\n".join(related) + "\n"
685
686
# TODO: does it make sense to add other sections? Maybe
687
# REPORTING ISSUES? LICENSE?
688
689
def msg(self, fname, name, args):
690
"""
691
Handles a single entry from kernel-doc parser.
692
693
Add a tail at the end of man pages output.
694
"""
695
super().msg(fname, name, args)
696
self.out_tail(fname, name, args)
697
698
return self.data
699
700
def output_highlight(self, block):
701
"""
702
Outputs a C symbol that may require being highlighted with
703
self.highlights variable using troff syntax.
704
"""
705
706
contents = self.highlight_block(block)
707
708
if isinstance(contents, list):
709
contents = "\n".join(contents)
710
711
for line in contents.strip("\n").split("\n"):
712
line = KernRe(r"^\s*").sub("", line)
713
if not line:
714
continue
715
716
if line[0] == ".":
717
self.data += "\\&" + line + "\n"
718
else:
719
self.data += line + "\n"
720
721
def out_doc(self, fname, name, args):
722
if not self.check_doc(name, args):
723
return
724
725
out_name = self.arg_name(args, name)
726
727
self.data += f'.TH "{self.modulename}" 9 "{out_name}" "{self.man_date}" "API Manual" LINUX' + "\n"
728
729
for section, text in args.sections.items():
730
self.data += f'.SH "{section}"' + "\n"
731
self.output_highlight(text)
732
733
def out_function(self, fname, name, args):
734
735
out_name = self.arg_name(args, name)
736
737
self.data += f'.TH "{name}" 9 "{out_name}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX' + "\n"
738
739
self.data += ".SH NAME\n"
740
self.data += f"{name} \\- {args['purpose']}\n"
741
742
self.data += ".SH SYNOPSIS\n"
743
if args.get('functiontype', ''):
744
self.data += f'.B "{args["functiontype"]}" {name}' + "\n"
745
else:
746
self.data += f'.B "{name}' + "\n"
747
748
count = 0
749
parenth = "("
750
post = ","
751
752
for parameter in args.parameterlist:
753
if count == len(args.parameterlist) - 1:
754
post = ");"
755
756
dtype = args.parametertypes.get(parameter, "")
757
if function_pointer.match(dtype):
758
# Pointer-to-function
759
self.data += f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"' + "\n"
760
else:
761
dtype = KernRe(r'([^\*])$').sub(r'\1 ', dtype)
762
763
self.data += f'.BI "{parenth}{dtype}" "{post}"' + "\n"
764
count += 1
765
parenth = ""
766
767
if args.parameterlist:
768
self.data += ".SH ARGUMENTS\n"
769
770
for parameter in args.parameterlist:
771
parameter_name = re.sub(r'\[.*', '', parameter)
772
773
self.data += f'.IP "{parameter}" 12' + "\n"
774
self.output_highlight(args.parameterdescs.get(parameter_name, ""))
775
776
for section, text in args.sections.items():
777
self.data += f'.SH "{section.upper()}"' + "\n"
778
self.output_highlight(text)
779
780
def out_enum(self, fname, name, args):
781
out_name = self.arg_name(args, name)
782
783
self.data += f'.TH "{self.modulename}" 9 "{out_name}" "{self.man_date}" "API Manual" LINUX' + "\n"
784
785
self.data += ".SH NAME\n"
786
self.data += f"enum {name} \\- {args['purpose']}\n"
787
788
self.data += ".SH SYNOPSIS\n"
789
self.data += f"enum {name}" + " {\n"
790
791
count = 0
792
for parameter in args.parameterlist:
793
self.data += f'.br\n.BI " {parameter}"' + "\n"
794
if count == len(args.parameterlist) - 1:
795
self.data += "\n};\n"
796
else:
797
self.data += ", \n.br\n"
798
799
count += 1
800
801
self.data += ".SH Constants\n"
802
803
for parameter in args.parameterlist:
804
parameter_name = KernRe(r'\[.*').sub('', parameter)
805
self.data += f'.IP "{parameter}" 12' + "\n"
806
self.output_highlight(args.parameterdescs.get(parameter_name, ""))
807
808
for section, text in args.sections.items():
809
self.data += f'.SH "{section}"' + "\n"
810
self.output_highlight(text)
811
812
def out_var(self, fname, name, args):
813
out_name = self.arg_name(args, name)
814
full_proto = args.other_stuff["full_proto"]
815
816
self.data += f'.TH "{self.modulename}" 9 "{out_name}" "{self.man_date}" "API Manual" LINUX' + "\n"
817
818
self.data += ".SH NAME\n"
819
self.data += f"{name} \\- {args['purpose']}\n"
820
821
self.data += ".SH SYNOPSIS\n"
822
self.data += f"{full_proto}\n"
823
824
if args.other_stuff["default_val"]:
825
self.data += f'.SH "Initialization"' + "\n"
826
self.output_highlight(f'default: {args.other_stuff["default_val"]}')
827
828
for section, text in args.sections.items():
829
self.data += f'.SH "{section}"' + "\n"
830
self.output_highlight(text)
831
832
def out_typedef(self, fname, name, args):
833
module = self.modulename
834
purpose = args.get('purpose')
835
out_name = self.arg_name(args, name)
836
837
self.data += f'.TH "{module}" 9 "{out_name}" "{self.man_date}" "API Manual" LINUX' + "\n"
838
839
self.data += ".SH NAME\n"
840
self.data += f"typedef {name} \\- {purpose}\n"
841
842
for section, text in args.sections.items():
843
self.data += f'.SH "{section}"' + "\n"
844
self.output_highlight(text)
845
846
def out_struct(self, fname, name, args):
847
module = self.modulename
848
purpose = args.get('purpose')
849
definition = args.get('definition')
850
out_name = self.arg_name(args, name)
851
852
self.data += f'.TH "{module}" 9 "{out_name}" "{self.man_date}" "API Manual" LINUX' + "\n"
853
854
self.data += ".SH NAME\n"
855
self.data += f"{args.type} {name} \\- {purpose}\n"
856
857
# Replace tabs with two spaces and handle newlines
858
declaration = definition.replace("\t", " ")
859
declaration = KernRe(r"\n").sub('"\n.br\n.BI "', declaration)
860
861
self.data += ".SH SYNOPSIS\n"
862
self.data += f"{args.type} {name} " + "{" + "\n.br\n"
863
self.data += f'.BI "{declaration}\n' + "};\n.br\n\n"
864
865
self.data += ".SH Members\n"
866
for parameter in args.parameterlist:
867
if parameter.startswith("#"):
868
continue
869
870
parameter_name = re.sub(r"\[.*", "", parameter)
871
872
if args.parameterdescs.get(parameter_name) == KernelDoc.undescribed:
873
continue
874
875
self.data += f'.IP "{parameter}" 12' + "\n"
876
self.output_highlight(args.parameterdescs.get(parameter_name))
877
878
for section, text in args.sections.items():
879
self.data += f'.SH "{section}"' + "\n"
880
self.output_highlight(text)
881
882