1d966dc65SMauro Carvalho Chehab#!/usr/bin/env python3 2d966dc65SMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0 3d966dc65SMauro Carvalho Chehab# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>. 4d966dc65SMauro Carvalho Chehab# 5d966dc65SMauro Carvalho Chehab# pylint: disable=C0301,C0302,R0904,R0912,R0913,R0914,R0915,R0917,R1702 6d966dc65SMauro Carvalho Chehab 7d966dc65SMauro Carvalho Chehab""" 8d966dc65SMauro Carvalho Chehabkdoc_parser 9d966dc65SMauro Carvalho Chehab=========== 10d966dc65SMauro Carvalho Chehab 11d966dc65SMauro Carvalho ChehabRead a C language source or header FILE and extract embedded 12d966dc65SMauro Carvalho Chehabdocumentation comments 13d966dc65SMauro Carvalho Chehab""" 14d966dc65SMauro Carvalho Chehab 15d966dc65SMauro Carvalho Chehabimport re 16d966dc65SMauro Carvalho Chehabfrom pprint import pformat 17d966dc65SMauro Carvalho Chehab 1804a383ceSMauro Carvalho Chehabfrom kdoc_re import NestedMatch, KernRe 19d966dc65SMauro Carvalho Chehab 20d966dc65SMauro Carvalho Chehab 21d966dc65SMauro Carvalho Chehab# 22d966dc65SMauro Carvalho Chehab# Regular expressions used to parse kernel-doc markups at KernelDoc class. 23d966dc65SMauro Carvalho Chehab# 24d966dc65SMauro Carvalho Chehab# Let's declare them in lowercase outside any class to make easier to 25d966dc65SMauro Carvalho Chehab# convert from the python script. 26d966dc65SMauro Carvalho Chehab# 27d966dc65SMauro Carvalho Chehab# As those are evaluated at the beginning, no need to cache them 28d966dc65SMauro Carvalho Chehab# 29d966dc65SMauro Carvalho Chehab 30d966dc65SMauro Carvalho Chehab# Allow whitespace at end of comment start. 3104a383ceSMauro Carvalho Chehabdoc_start = KernRe(r'^/\*\*\s*$', cache=False) 32d966dc65SMauro Carvalho Chehab 3304a383ceSMauro Carvalho Chehabdoc_end = KernRe(r'\*/', cache=False) 3404a383ceSMauro Carvalho Chehabdoc_com = KernRe(r'\s*\*\s*', cache=False) 3504a383ceSMauro Carvalho Chehabdoc_com_body = KernRe(r'\s*\* ?', cache=False) 3604a383ceSMauro Carvalho Chehabdoc_decl = doc_com + KernRe(r'(\w+)', cache=False) 37d966dc65SMauro Carvalho Chehab 38d966dc65SMauro Carvalho Chehab# @params and a strictly limited set of supported section names 39d966dc65SMauro Carvalho Chehab# Specifically: 40d966dc65SMauro Carvalho Chehab# Match @word: 41d966dc65SMauro Carvalho Chehab# @...: 42d966dc65SMauro Carvalho Chehab# @{section-name}: 43d966dc65SMauro Carvalho Chehab# while trying to not match literal block starts like "example::" 44d966dc65SMauro Carvalho Chehab# 45d966dc65SMauro Carvalho Chehabdoc_sect = doc_com + \ 4604a383ceSMauro Carvalho Chehab KernRe(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$', 47d966dc65SMauro Carvalho Chehab flags=re.I, cache=False) 48d966dc65SMauro Carvalho Chehab 4904a383ceSMauro Carvalho Chehabdoc_content = doc_com_body + KernRe(r'(.*)', cache=False) 5004a383ceSMauro Carvalho Chehabdoc_block = doc_com + KernRe(r'DOC:\s*(.*)?', cache=False) 5104a383ceSMauro Carvalho Chehabdoc_inline_start = KernRe(r'^\s*/\*\*\s*$', cache=False) 5204a383ceSMauro Carvalho Chehabdoc_inline_sect = KernRe(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False) 5304a383ceSMauro Carvalho Chehabdoc_inline_end = KernRe(r'^\s*\*/\s*$', cache=False) 5404a383ceSMauro Carvalho Chehabdoc_inline_oneline = KernRe(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False) 5504a383ceSMauro Carvalho Chehabattribute = KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", 56d966dc65SMauro Carvalho Chehab flags=re.I | re.S, cache=False) 57d966dc65SMauro Carvalho Chehab 5804a383ceSMauro Carvalho Chehabexport_symbol = KernRe(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False) 5904a383ceSMauro Carvalho Chehabexport_symbol_ns = KernRe(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False) 60d966dc65SMauro Carvalho Chehab 6104a383ceSMauro Carvalho Chehabtype_param = KernRe(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False) 62d966dc65SMauro Carvalho Chehab 63f9cdbc57SMauro Carvalho Chehabclass state: 64d966dc65SMauro Carvalho Chehab """ 65f9cdbc57SMauro Carvalho Chehab State machine enums 66d966dc65SMauro Carvalho Chehab """ 67d966dc65SMauro Carvalho Chehab 68d966dc65SMauro Carvalho Chehab # Parser states 69f9cdbc57SMauro Carvalho Chehab NORMAL = 0 # normal code 70f9cdbc57SMauro Carvalho Chehab NAME = 1 # looking for function name 71f9cdbc57SMauro Carvalho Chehab BODY_MAYBE = 2 # body - or maybe more description 72f9cdbc57SMauro Carvalho Chehab BODY = 3 # the body of the comment 73f9cdbc57SMauro Carvalho Chehab BODY_WITH_BLANK_LINE = 4 # the body which has a blank line 74f9cdbc57SMauro Carvalho Chehab PROTO = 5 # scanning prototype 75f9cdbc57SMauro Carvalho Chehab DOCBLOCK = 6 # documentation block 76f9cdbc57SMauro Carvalho Chehab INLINE = 7 # gathering doc outside main block 77d966dc65SMauro Carvalho Chehab 78f9cdbc57SMauro Carvalho Chehab name = [ 79d966dc65SMauro Carvalho Chehab "NORMAL", 80d966dc65SMauro Carvalho Chehab "NAME", 81d966dc65SMauro Carvalho Chehab "BODY_MAYBE", 82d966dc65SMauro Carvalho Chehab "BODY", 83d966dc65SMauro Carvalho Chehab "BODY_WITH_BLANK_LINE", 84d966dc65SMauro Carvalho Chehab "PROTO", 85d966dc65SMauro Carvalho Chehab "DOCBLOCK", 86d966dc65SMauro Carvalho Chehab "INLINE", 87d966dc65SMauro Carvalho Chehab ] 88d966dc65SMauro Carvalho Chehab 89d966dc65SMauro Carvalho Chehab # Inline documentation state 90f9cdbc57SMauro Carvalho Chehab INLINE_NA = 0 # not applicable ($state != INLINE) 91f9cdbc57SMauro Carvalho Chehab INLINE_NAME = 1 # looking for member name (@foo:) 92f9cdbc57SMauro Carvalho Chehab INLINE_TEXT = 2 # looking for member documentation 93f9cdbc57SMauro Carvalho Chehab INLINE_END = 3 # done 94f9cdbc57SMauro Carvalho Chehab INLINE_ERROR = 4 # error - Comment without header was found. 95d966dc65SMauro Carvalho Chehab # Spit a warning as it's not 96d966dc65SMauro Carvalho Chehab # proper kernel-doc and ignore the rest. 97d966dc65SMauro Carvalho Chehab 98f9cdbc57SMauro Carvalho Chehab inline_name = [ 99d966dc65SMauro Carvalho Chehab "", 100d966dc65SMauro Carvalho Chehab "_NAME", 101d966dc65SMauro Carvalho Chehab "_TEXT", 102d966dc65SMauro Carvalho Chehab "_END", 103d966dc65SMauro Carvalho Chehab "_ERROR", 104d966dc65SMauro Carvalho Chehab ] 105d966dc65SMauro Carvalho Chehab 106*e3b42e94SMauro Carvalho ChehabSECTION_DEFAULT = "Description" # default section 107*e3b42e94SMauro Carvalho Chehab 108*e3b42e94SMauro Carvalho Chehabclass KernelEntry: 109*e3b42e94SMauro Carvalho Chehab 110*e3b42e94SMauro Carvalho Chehab def __init__(self, config, ln): 111*e3b42e94SMauro Carvalho Chehab self.config = config 112*e3b42e94SMauro Carvalho Chehab 113*e3b42e94SMauro Carvalho Chehab self.contents = "" 114*e3b42e94SMauro Carvalho Chehab self.function = "" 115*e3b42e94SMauro Carvalho Chehab self.sectcheck = "" 116*e3b42e94SMauro Carvalho Chehab self.struct_actual = "" 117*e3b42e94SMauro Carvalho Chehab self.prototype = "" 118*e3b42e94SMauro Carvalho Chehab 119*e3b42e94SMauro Carvalho Chehab self.warnings = [] 120*e3b42e94SMauro Carvalho Chehab 121*e3b42e94SMauro Carvalho Chehab self.parameterlist = [] 122*e3b42e94SMauro Carvalho Chehab self.parameterdescs = {} 123*e3b42e94SMauro Carvalho Chehab self.parametertypes = {} 124*e3b42e94SMauro Carvalho Chehab self.parameterdesc_start_lines = {} 125*e3b42e94SMauro Carvalho Chehab 126*e3b42e94SMauro Carvalho Chehab self.section_start_lines = {} 127*e3b42e94SMauro Carvalho Chehab self.sectionlist = [] 128*e3b42e94SMauro Carvalho Chehab self.sections = {} 129*e3b42e94SMauro Carvalho Chehab 130*e3b42e94SMauro Carvalho Chehab self.anon_struct_union = False 131*e3b42e94SMauro Carvalho Chehab 132*e3b42e94SMauro Carvalho Chehab self.leading_space = None 133*e3b42e94SMauro Carvalho Chehab 134*e3b42e94SMauro Carvalho Chehab # State flags 135*e3b42e94SMauro Carvalho Chehab self.brcount = 0 136*e3b42e94SMauro Carvalho Chehab 137*e3b42e94SMauro Carvalho Chehab self.in_doc_sect = False 138*e3b42e94SMauro Carvalho Chehab self.declaration_start_line = ln + 1 139*e3b42e94SMauro Carvalho Chehab 140*e3b42e94SMauro Carvalho Chehab # TODO: rename to emit_message after removal of kernel-doc.pl 141*e3b42e94SMauro Carvalho Chehab def emit_msg(self, log_msg, warning=True): 142*e3b42e94SMauro Carvalho Chehab """Emit a message""" 143*e3b42e94SMauro Carvalho Chehab 144*e3b42e94SMauro Carvalho Chehab if not warning: 145*e3b42e94SMauro Carvalho Chehab self.config.log.info(log_msg) 146*e3b42e94SMauro Carvalho Chehab return 147*e3b42e94SMauro Carvalho Chehab 148*e3b42e94SMauro Carvalho Chehab # Delegate warning output to output logic, as this way it 149*e3b42e94SMauro Carvalho Chehab # will report warnings/info only for symbols that are output 150*e3b42e94SMauro Carvalho Chehab 151*e3b42e94SMauro Carvalho Chehab self.warnings.append(log_msg) 152*e3b42e94SMauro Carvalho Chehab return 153*e3b42e94SMauro Carvalho Chehab 154*e3b42e94SMauro Carvalho Chehab def dump_section(self, start_new=True): 155*e3b42e94SMauro Carvalho Chehab """ 156*e3b42e94SMauro Carvalho Chehab Dumps section contents to arrays/hashes intended for that purpose. 157*e3b42e94SMauro Carvalho Chehab """ 158*e3b42e94SMauro Carvalho Chehab 159*e3b42e94SMauro Carvalho Chehab name = self.section 160*e3b42e94SMauro Carvalho Chehab contents = self.contents 161*e3b42e94SMauro Carvalho Chehab 162*e3b42e94SMauro Carvalho Chehab if type_param.match(name): 163*e3b42e94SMauro Carvalho Chehab name = type_param.group(1) 164*e3b42e94SMauro Carvalho Chehab 165*e3b42e94SMauro Carvalho Chehab self.parameterdescs[name] = contents 166*e3b42e94SMauro Carvalho Chehab self.parameterdesc_start_lines[name] = self.new_start_line 167*e3b42e94SMauro Carvalho Chehab 168*e3b42e94SMauro Carvalho Chehab self.sectcheck += name + " " 169*e3b42e94SMauro Carvalho Chehab self.new_start_line = 0 170*e3b42e94SMauro Carvalho Chehab 171*e3b42e94SMauro Carvalho Chehab elif name == "@...": 172*e3b42e94SMauro Carvalho Chehab name = "..." 173*e3b42e94SMauro Carvalho Chehab self.parameterdescs[name] = contents 174*e3b42e94SMauro Carvalho Chehab self.sectcheck += name + " " 175*e3b42e94SMauro Carvalho Chehab self.parameterdesc_start_lines[name] = self.new_start_line 176*e3b42e94SMauro Carvalho Chehab self.new_start_line = 0 177*e3b42e94SMauro Carvalho Chehab 178*e3b42e94SMauro Carvalho Chehab else: 179*e3b42e94SMauro Carvalho Chehab if name in self.sections and self.sections[name] != "": 180*e3b42e94SMauro Carvalho Chehab # Only warn on user-specified duplicate section names 181*e3b42e94SMauro Carvalho Chehab if name != SECTION_DEFAULT: 182*e3b42e94SMauro Carvalho Chehab self.emit_msg(self.new_start_line, 183*e3b42e94SMauro Carvalho Chehab f"duplicate section name '{name}'\n") 184*e3b42e94SMauro Carvalho Chehab self.sections[name] += contents 185*e3b42e94SMauro Carvalho Chehab else: 186*e3b42e94SMauro Carvalho Chehab self.sections[name] = contents 187*e3b42e94SMauro Carvalho Chehab self.sectionlist.append(name) 188*e3b42e94SMauro Carvalho Chehab self.section_start_lines[name] = self.new_start_line 189*e3b42e94SMauro Carvalho Chehab self.new_start_line = 0 190*e3b42e94SMauro Carvalho Chehab 191*e3b42e94SMauro Carvalho Chehab# self.config.log.debug("Section: %s : %s", name, pformat(vars(self))) 192*e3b42e94SMauro Carvalho Chehab 193*e3b42e94SMauro Carvalho Chehab if start_new: 194*e3b42e94SMauro Carvalho Chehab self.section = SECTION_DEFAULT 195*e3b42e94SMauro Carvalho Chehab self.contents = "" 196*e3b42e94SMauro Carvalho Chehab 197f9cdbc57SMauro Carvalho Chehab 198f9cdbc57SMauro Carvalho Chehabclass KernelDoc: 199f9cdbc57SMauro Carvalho Chehab """ 200f9cdbc57SMauro Carvalho Chehab Read a C language source or header FILE and extract embedded 201f9cdbc57SMauro Carvalho Chehab documentation comments. 202f9cdbc57SMauro Carvalho Chehab """ 203f9cdbc57SMauro Carvalho Chehab 204d966dc65SMauro Carvalho Chehab # Section names 205d966dc65SMauro Carvalho Chehab 206d966dc65SMauro Carvalho Chehab section_intro = "Introduction" 207d966dc65SMauro Carvalho Chehab section_context = "Context" 208d966dc65SMauro Carvalho Chehab section_return = "Return" 209d966dc65SMauro Carvalho Chehab 210d966dc65SMauro Carvalho Chehab undescribed = "-- undescribed --" 211d966dc65SMauro Carvalho Chehab 212d966dc65SMauro Carvalho Chehab def __init__(self, config, fname): 213d966dc65SMauro Carvalho Chehab """Initialize internal variables""" 214d966dc65SMauro Carvalho Chehab 215d966dc65SMauro Carvalho Chehab self.fname = fname 216d966dc65SMauro Carvalho Chehab self.config = config 217d966dc65SMauro Carvalho Chehab 218d966dc65SMauro Carvalho Chehab # Initial state for the state machines 219f9cdbc57SMauro Carvalho Chehab self.state = state.NORMAL 220f9cdbc57SMauro Carvalho Chehab self.inline_doc_state = state.INLINE_NA 221d966dc65SMauro Carvalho Chehab 222d966dc65SMauro Carvalho Chehab # Store entry currently being processed 223d966dc65SMauro Carvalho Chehab self.entry = None 224d966dc65SMauro Carvalho Chehab 225d966dc65SMauro Carvalho Chehab # Place all potential outputs into an array 226d966dc65SMauro Carvalho Chehab self.entries = [] 227d966dc65SMauro Carvalho Chehab 228*e3b42e94SMauro Carvalho Chehab def emit_msg(self, ln, msg, warning=True): 229d966dc65SMauro Carvalho Chehab """Emit a message""" 230d966dc65SMauro Carvalho Chehab 2319cbc2d3bSMauro Carvalho Chehab log_msg = f"{self.fname}:{ln} {msg}" 2329cbc2d3bSMauro Carvalho Chehab 2339cbc2d3bSMauro Carvalho Chehab if self.entry: 234*e3b42e94SMauro Carvalho Chehab self.entry.emit_msg(log_msg, warning) 2359cbc2d3bSMauro Carvalho Chehab return 2369cbc2d3bSMauro Carvalho Chehab 237*e3b42e94SMauro Carvalho Chehab if warning: 2389cbc2d3bSMauro Carvalho Chehab self.config.log.warning(log_msg) 239*e3b42e94SMauro Carvalho Chehab else: 240*e3b42e94SMauro Carvalho Chehab self.config.log.info(log_msg) 241d966dc65SMauro Carvalho Chehab 242d966dc65SMauro Carvalho Chehab def dump_section(self, start_new=True): 243d966dc65SMauro Carvalho Chehab """ 244d966dc65SMauro Carvalho Chehab Dumps section contents to arrays/hashes intended for that purpose. 245d966dc65SMauro Carvalho Chehab """ 246d966dc65SMauro Carvalho Chehab 247*e3b42e94SMauro Carvalho Chehab if self.entry: 248*e3b42e94SMauro Carvalho Chehab self.entry.dump_section(start_new) 249d966dc65SMauro Carvalho Chehab 250485f6f79SMauro Carvalho Chehab # TODO: rename it to store_declaration after removal of kernel-doc.pl 251d966dc65SMauro Carvalho Chehab def output_declaration(self, dtype, name, **args): 252d966dc65SMauro Carvalho Chehab """ 253d966dc65SMauro Carvalho Chehab Stores the entry into an entry array. 254d966dc65SMauro Carvalho Chehab 255d966dc65SMauro Carvalho Chehab The actual output and output filters will be handled elsewhere 256d966dc65SMauro Carvalho Chehab """ 257d966dc65SMauro Carvalho Chehab 258d966dc65SMauro Carvalho Chehab # The implementation here is different than the original kernel-doc: 259d966dc65SMauro Carvalho Chehab # instead of checking for output filters or actually output anything, 260d966dc65SMauro Carvalho Chehab # it just stores the declaration content at self.entries, as the 261d966dc65SMauro Carvalho Chehab # output will happen on a separate class. 262d966dc65SMauro Carvalho Chehab # 263d966dc65SMauro Carvalho Chehab # For now, we're keeping the same name of the function just to make 264d966dc65SMauro Carvalho Chehab # easier to compare the source code of both scripts 265d966dc65SMauro Carvalho Chehab 266d966dc65SMauro Carvalho Chehab args["declaration_start_line"] = self.entry.declaration_start_line 267d966dc65SMauro Carvalho Chehab args["type"] = dtype 2689cbc2d3bSMauro Carvalho Chehab args["warnings"] = self.entry.warnings 269d966dc65SMauro Carvalho Chehab 270485f6f79SMauro Carvalho Chehab # TODO: use colletions.OrderedDict to remove sectionlist 271d966dc65SMauro Carvalho Chehab 272d966dc65SMauro Carvalho Chehab sections = args.get('sections', {}) 273d966dc65SMauro Carvalho Chehab sectionlist = args.get('sectionlist', []) 274d966dc65SMauro Carvalho Chehab 275d966dc65SMauro Carvalho Chehab # Drop empty sections 276485f6f79SMauro Carvalho Chehab # TODO: improve empty sections logic to emit warnings 277d966dc65SMauro Carvalho Chehab for section in ["Description", "Return"]: 278d966dc65SMauro Carvalho Chehab if section in sectionlist: 279d966dc65SMauro Carvalho Chehab if not sections[section].rstrip(): 280d966dc65SMauro Carvalho Chehab del sections[section] 281d966dc65SMauro Carvalho Chehab sectionlist.remove(section) 282d966dc65SMauro Carvalho Chehab 283d966dc65SMauro Carvalho Chehab self.entries.append((name, args)) 284d966dc65SMauro Carvalho Chehab 285d966dc65SMauro Carvalho Chehab self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args)) 286d966dc65SMauro Carvalho Chehab 287d966dc65SMauro Carvalho Chehab def reset_state(self, ln): 288d966dc65SMauro Carvalho Chehab """ 289d966dc65SMauro Carvalho Chehab Ancillary routine to create a new entry. It initializes all 290d966dc65SMauro Carvalho Chehab variables used by the state machine. 291d966dc65SMauro Carvalho Chehab """ 292d966dc65SMauro Carvalho Chehab 293*e3b42e94SMauro Carvalho Chehab self.entry = KernelEntry(self.config, ln) 294d966dc65SMauro Carvalho Chehab 295d966dc65SMauro Carvalho Chehab # State flags 296f9cdbc57SMauro Carvalho Chehab self.state = state.NORMAL 297f9cdbc57SMauro Carvalho Chehab self.inline_doc_state = state.INLINE_NA 298d966dc65SMauro Carvalho Chehab 299d966dc65SMauro Carvalho Chehab def push_parameter(self, ln, decl_type, param, dtype, 300d966dc65SMauro Carvalho Chehab org_arg, declaration_name): 301d966dc65SMauro Carvalho Chehab """ 302d966dc65SMauro Carvalho Chehab Store parameters and their descriptions at self.entry. 303d966dc65SMauro Carvalho Chehab """ 304d966dc65SMauro Carvalho Chehab 305d966dc65SMauro Carvalho Chehab if self.entry.anon_struct_union and dtype == "" and param == "}": 306d966dc65SMauro Carvalho Chehab return # Ignore the ending }; from anonymous struct/union 307d966dc65SMauro Carvalho Chehab 308d966dc65SMauro Carvalho Chehab self.entry.anon_struct_union = False 309d966dc65SMauro Carvalho Chehab 31004a383ceSMauro Carvalho Chehab param = KernRe(r'[\[\)].*').sub('', param, count=1) 311d966dc65SMauro Carvalho Chehab 312d966dc65SMauro Carvalho Chehab if dtype == "" and param.endswith("..."): 31304a383ceSMauro Carvalho Chehab if KernRe(r'\w\.\.\.$').search(param): 314d966dc65SMauro Carvalho Chehab # For named variable parameters of the form `x...`, 315d966dc65SMauro Carvalho Chehab # remove the dots 316d966dc65SMauro Carvalho Chehab param = param[:-3] 317d966dc65SMauro Carvalho Chehab else: 318d966dc65SMauro Carvalho Chehab # Handles unnamed variable parameters 319d966dc65SMauro Carvalho Chehab param = "..." 320d966dc65SMauro Carvalho Chehab 321d966dc65SMauro Carvalho Chehab if param not in self.entry.parameterdescs or \ 322d966dc65SMauro Carvalho Chehab not self.entry.parameterdescs[param]: 323d966dc65SMauro Carvalho Chehab 324d966dc65SMauro Carvalho Chehab self.entry.parameterdescs[param] = "variable arguments" 325d966dc65SMauro Carvalho Chehab 326d966dc65SMauro Carvalho Chehab elif dtype == "" and (not param or param == "void"): 327d966dc65SMauro Carvalho Chehab param = "void" 328d966dc65SMauro Carvalho Chehab self.entry.parameterdescs[param] = "no arguments" 329d966dc65SMauro Carvalho Chehab 330d966dc65SMauro Carvalho Chehab elif dtype == "" and param in ["struct", "union"]: 331d966dc65SMauro Carvalho Chehab # Handle unnamed (anonymous) union or struct 332d966dc65SMauro Carvalho Chehab dtype = param 333d966dc65SMauro Carvalho Chehab param = "{unnamed_" + param + "}" 334d966dc65SMauro Carvalho Chehab self.entry.parameterdescs[param] = "anonymous\n" 335d966dc65SMauro Carvalho Chehab self.entry.anon_struct_union = True 336d966dc65SMauro Carvalho Chehab 337d966dc65SMauro Carvalho Chehab # Handle cache group enforcing variables: they do not need 338d966dc65SMauro Carvalho Chehab # to be described in header files 339d966dc65SMauro Carvalho Chehab elif "__cacheline_group" in param: 340d966dc65SMauro Carvalho Chehab # Ignore __cacheline_group_begin and __cacheline_group_end 341d966dc65SMauro Carvalho Chehab return 342d966dc65SMauro Carvalho Chehab 343d966dc65SMauro Carvalho Chehab # Warn if parameter has no description 344d966dc65SMauro Carvalho Chehab # (but ignore ones starting with # as these are not parameters 345d966dc65SMauro Carvalho Chehab # but inline preprocessor statements) 346d966dc65SMauro Carvalho Chehab if param not in self.entry.parameterdescs and not param.startswith("#"): 347d966dc65SMauro Carvalho Chehab self.entry.parameterdescs[param] = self.undescribed 348d966dc65SMauro Carvalho Chehab 3499cbc2d3bSMauro Carvalho Chehab if "." not in param: 350d966dc65SMauro Carvalho Chehab if decl_type == 'function': 351d966dc65SMauro Carvalho Chehab dname = f"{decl_type} parameter" 352d966dc65SMauro Carvalho Chehab else: 353d966dc65SMauro Carvalho Chehab dname = f"{decl_type} member" 354d966dc65SMauro Carvalho Chehab 355*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 356d966dc65SMauro Carvalho Chehab f"{dname} '{param}' not described in '{declaration_name}'") 357d966dc65SMauro Carvalho Chehab 358d966dc65SMauro Carvalho Chehab # Strip spaces from param so that it is one continuous string on 359d966dc65SMauro Carvalho Chehab # parameterlist. This fixes a problem where check_sections() 360d966dc65SMauro Carvalho Chehab # cannot find a parameter like "addr[6 + 2]" because it actually 361d966dc65SMauro Carvalho Chehab # appears as "addr[6", "+", "2]" on the parameter list. 362d966dc65SMauro Carvalho Chehab # However, it's better to maintain the param string unchanged for 363d966dc65SMauro Carvalho Chehab # output, so just weaken the string compare in check_sections() 364d966dc65SMauro Carvalho Chehab # to ignore "[blah" in a parameter string. 365d966dc65SMauro Carvalho Chehab 366d966dc65SMauro Carvalho Chehab self.entry.parameterlist.append(param) 36704a383ceSMauro Carvalho Chehab org_arg = KernRe(r'\s\s+').sub(' ', org_arg) 368d966dc65SMauro Carvalho Chehab self.entry.parametertypes[param] = org_arg 369d966dc65SMauro Carvalho Chehab 370d966dc65SMauro Carvalho Chehab def save_struct_actual(self, actual): 371d966dc65SMauro Carvalho Chehab """ 372d966dc65SMauro Carvalho Chehab Strip all spaces from the actual param so that it looks like 373d966dc65SMauro Carvalho Chehab one string item. 374d966dc65SMauro Carvalho Chehab """ 375d966dc65SMauro Carvalho Chehab 37604a383ceSMauro Carvalho Chehab actual = KernRe(r'\s*').sub("", actual, count=1) 377d966dc65SMauro Carvalho Chehab 378d966dc65SMauro Carvalho Chehab self.entry.struct_actual += actual + " " 379d966dc65SMauro Carvalho Chehab 380d966dc65SMauro Carvalho Chehab def create_parameter_list(self, ln, decl_type, args, 381d966dc65SMauro Carvalho Chehab splitter, declaration_name): 382d966dc65SMauro Carvalho Chehab """ 383d966dc65SMauro Carvalho Chehab Creates a list of parameters, storing them at self.entry. 384d966dc65SMauro Carvalho Chehab """ 385d966dc65SMauro Carvalho Chehab 386d966dc65SMauro Carvalho Chehab # temporarily replace all commas inside function pointer definition 38704a383ceSMauro Carvalho Chehab arg_expr = KernRe(r'(\([^\),]+),') 388d966dc65SMauro Carvalho Chehab while arg_expr.search(args): 389d966dc65SMauro Carvalho Chehab args = arg_expr.sub(r"\1#", args) 390d966dc65SMauro Carvalho Chehab 391d966dc65SMauro Carvalho Chehab for arg in args.split(splitter): 392d966dc65SMauro Carvalho Chehab # Strip comments 39304a383ceSMauro Carvalho Chehab arg = KernRe(r'\/\*.*\*\/').sub('', arg) 394d966dc65SMauro Carvalho Chehab 395d966dc65SMauro Carvalho Chehab # Ignore argument attributes 39604a383ceSMauro Carvalho Chehab arg = KernRe(r'\sPOS0?\s').sub(' ', arg) 397d966dc65SMauro Carvalho Chehab 398d966dc65SMauro Carvalho Chehab # Strip leading/trailing spaces 399d966dc65SMauro Carvalho Chehab arg = arg.strip() 40004a383ceSMauro Carvalho Chehab arg = KernRe(r'\s+').sub(' ', arg, count=1) 401d966dc65SMauro Carvalho Chehab 402d966dc65SMauro Carvalho Chehab if arg.startswith('#'): 403d966dc65SMauro Carvalho Chehab # Treat preprocessor directive as a typeless variable just to fill 404d966dc65SMauro Carvalho Chehab # corresponding data structures "correctly". Catch it later in 405d966dc65SMauro Carvalho Chehab # output_* subs. 406d966dc65SMauro Carvalho Chehab 407d966dc65SMauro Carvalho Chehab # Treat preprocessor directive as a typeless variable 408d966dc65SMauro Carvalho Chehab self.push_parameter(ln, decl_type, arg, "", 409d966dc65SMauro Carvalho Chehab "", declaration_name) 410d966dc65SMauro Carvalho Chehab 41104a383ceSMauro Carvalho Chehab elif KernRe(r'\(.+\)\s*\(').search(arg): 412d966dc65SMauro Carvalho Chehab # Pointer-to-function 413d966dc65SMauro Carvalho Chehab 414d966dc65SMauro Carvalho Chehab arg = arg.replace('#', ',') 415d966dc65SMauro Carvalho Chehab 41604a383ceSMauro Carvalho Chehab r = KernRe(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)') 417d966dc65SMauro Carvalho Chehab if r.match(arg): 418d966dc65SMauro Carvalho Chehab param = r.group(1) 419d966dc65SMauro Carvalho Chehab else: 420*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"Invalid param: {arg}") 421d966dc65SMauro Carvalho Chehab param = arg 422d966dc65SMauro Carvalho Chehab 42304a383ceSMauro Carvalho Chehab dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) 424d966dc65SMauro Carvalho Chehab self.save_struct_actual(param) 425d966dc65SMauro Carvalho Chehab self.push_parameter(ln, decl_type, param, dtype, 426d966dc65SMauro Carvalho Chehab arg, declaration_name) 427d966dc65SMauro Carvalho Chehab 42804a383ceSMauro Carvalho Chehab elif KernRe(r'\(.+\)\s*\[').search(arg): 429d966dc65SMauro Carvalho Chehab # Array-of-pointers 430d966dc65SMauro Carvalho Chehab 431d966dc65SMauro Carvalho Chehab arg = arg.replace('#', ',') 43204a383ceSMauro Carvalho Chehab r = KernRe(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)') 433d966dc65SMauro Carvalho Chehab if r.match(arg): 434d966dc65SMauro Carvalho Chehab param = r.group(1) 435d966dc65SMauro Carvalho Chehab else: 436*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"Invalid param: {arg}") 437d966dc65SMauro Carvalho Chehab param = arg 438d966dc65SMauro Carvalho Chehab 43904a383ceSMauro Carvalho Chehab dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) 440d966dc65SMauro Carvalho Chehab 441d966dc65SMauro Carvalho Chehab self.save_struct_actual(param) 442d966dc65SMauro Carvalho Chehab self.push_parameter(ln, decl_type, param, dtype, 443d966dc65SMauro Carvalho Chehab arg, declaration_name) 444d966dc65SMauro Carvalho Chehab 445d966dc65SMauro Carvalho Chehab elif arg: 44604a383ceSMauro Carvalho Chehab arg = KernRe(r'\s*:\s*').sub(":", arg) 44704a383ceSMauro Carvalho Chehab arg = KernRe(r'\s*\[').sub('[', arg) 448d966dc65SMauro Carvalho Chehab 44904a383ceSMauro Carvalho Chehab args = KernRe(r'\s*,\s*').split(arg) 450d966dc65SMauro Carvalho Chehab if args[0] and '*' in args[0]: 451d966dc65SMauro Carvalho Chehab args[0] = re.sub(r'(\*+)\s*', r' \1', args[0]) 452d966dc65SMauro Carvalho Chehab 453d966dc65SMauro Carvalho Chehab first_arg = [] 45404a383ceSMauro Carvalho Chehab r = KernRe(r'^(.*\s+)(.*?\[.*\].*)$') 455d966dc65SMauro Carvalho Chehab if args[0] and r.match(args[0]): 456d966dc65SMauro Carvalho Chehab args.pop(0) 457d966dc65SMauro Carvalho Chehab first_arg.extend(r.group(1)) 458d966dc65SMauro Carvalho Chehab first_arg.append(r.group(2)) 459d966dc65SMauro Carvalho Chehab else: 46004a383ceSMauro Carvalho Chehab first_arg = KernRe(r'\s+').split(args.pop(0)) 461d966dc65SMauro Carvalho Chehab 462d966dc65SMauro Carvalho Chehab args.insert(0, first_arg.pop()) 463d966dc65SMauro Carvalho Chehab dtype = ' '.join(first_arg) 464d966dc65SMauro Carvalho Chehab 465d966dc65SMauro Carvalho Chehab for param in args: 46604a383ceSMauro Carvalho Chehab if KernRe(r'^(\*+)\s*(.*)').match(param): 46704a383ceSMauro Carvalho Chehab r = KernRe(r'^(\*+)\s*(.*)') 468d966dc65SMauro Carvalho Chehab if not r.match(param): 469*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"Invalid param: {param}") 470d966dc65SMauro Carvalho Chehab continue 471d966dc65SMauro Carvalho Chehab 472d966dc65SMauro Carvalho Chehab param = r.group(1) 473d966dc65SMauro Carvalho Chehab 474d966dc65SMauro Carvalho Chehab self.save_struct_actual(r.group(2)) 475d966dc65SMauro Carvalho Chehab self.push_parameter(ln, decl_type, r.group(2), 476d966dc65SMauro Carvalho Chehab f"{dtype} {r.group(1)}", 477d966dc65SMauro Carvalho Chehab arg, declaration_name) 478d966dc65SMauro Carvalho Chehab 47904a383ceSMauro Carvalho Chehab elif KernRe(r'(.*?):(\w+)').search(param): 48004a383ceSMauro Carvalho Chehab r = KernRe(r'(.*?):(\w+)') 481d966dc65SMauro Carvalho Chehab if not r.match(param): 482*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"Invalid param: {param}") 483d966dc65SMauro Carvalho Chehab continue 484d966dc65SMauro Carvalho Chehab 485d966dc65SMauro Carvalho Chehab if dtype != "": # Skip unnamed bit-fields 486d966dc65SMauro Carvalho Chehab self.save_struct_actual(r.group(1)) 487d966dc65SMauro Carvalho Chehab self.push_parameter(ln, decl_type, r.group(1), 488d966dc65SMauro Carvalho Chehab f"{dtype}:{r.group(2)}", 489d966dc65SMauro Carvalho Chehab arg, declaration_name) 490d966dc65SMauro Carvalho Chehab else: 491d966dc65SMauro Carvalho Chehab self.save_struct_actual(param) 492d966dc65SMauro Carvalho Chehab self.push_parameter(ln, decl_type, param, dtype, 493d966dc65SMauro Carvalho Chehab arg, declaration_name) 494d966dc65SMauro Carvalho Chehab 495d966dc65SMauro Carvalho Chehab def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck): 496d966dc65SMauro Carvalho Chehab """ 497d966dc65SMauro Carvalho Chehab Check for errors inside sections, emitting warnings if not found 498d966dc65SMauro Carvalho Chehab parameters are described. 499d966dc65SMauro Carvalho Chehab """ 500d966dc65SMauro Carvalho Chehab 501d966dc65SMauro Carvalho Chehab sects = sectcheck.split() 502d966dc65SMauro Carvalho Chehab prms = prmscheck.split() 503d966dc65SMauro Carvalho Chehab err = False 504d966dc65SMauro Carvalho Chehab 505d966dc65SMauro Carvalho Chehab for sx in range(len(sects)): # pylint: disable=C0200 506d966dc65SMauro Carvalho Chehab err = True 507d966dc65SMauro Carvalho Chehab for px in range(len(prms)): # pylint: disable=C0200 508d966dc65SMauro Carvalho Chehab prm_clean = prms[px] 50904a383ceSMauro Carvalho Chehab prm_clean = KernRe(r'\[.*\]').sub('', prm_clean) 510d966dc65SMauro Carvalho Chehab prm_clean = attribute.sub('', prm_clean) 511d966dc65SMauro Carvalho Chehab 512d966dc65SMauro Carvalho Chehab # ignore array size in a parameter string; 513d966dc65SMauro Carvalho Chehab # however, the original param string may contain 514d966dc65SMauro Carvalho Chehab # spaces, e.g.: addr[6 + 2] 515d966dc65SMauro Carvalho Chehab # and this appears in @prms as "addr[6" since the 516d966dc65SMauro Carvalho Chehab # parameter list is split at spaces; 517d966dc65SMauro Carvalho Chehab # hence just ignore "[..." for the sections check; 51804a383ceSMauro Carvalho Chehab prm_clean = KernRe(r'\[.*').sub('', prm_clean) 519d966dc65SMauro Carvalho Chehab 520d966dc65SMauro Carvalho Chehab if prm_clean == sects[sx]: 521d966dc65SMauro Carvalho Chehab err = False 522d966dc65SMauro Carvalho Chehab break 523d966dc65SMauro Carvalho Chehab 524d966dc65SMauro Carvalho Chehab if err: 525d966dc65SMauro Carvalho Chehab if decl_type == 'function': 526d966dc65SMauro Carvalho Chehab dname = f"{decl_type} parameter" 527d966dc65SMauro Carvalho Chehab else: 528d966dc65SMauro Carvalho Chehab dname = f"{decl_type} member" 529d966dc65SMauro Carvalho Chehab 530*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 531d966dc65SMauro Carvalho Chehab f"Excess {dname} '{sects[sx]}' description in '{decl_name}'") 532d966dc65SMauro Carvalho Chehab 533d966dc65SMauro Carvalho Chehab def check_return_section(self, ln, declaration_name, return_type): 534d966dc65SMauro Carvalho Chehab """ 535d966dc65SMauro Carvalho Chehab If the function doesn't return void, warns about the lack of a 536d966dc65SMauro Carvalho Chehab return description. 537d966dc65SMauro Carvalho Chehab """ 538d966dc65SMauro Carvalho Chehab 539d966dc65SMauro Carvalho Chehab if not self.config.wreturn: 540d966dc65SMauro Carvalho Chehab return 541d966dc65SMauro Carvalho Chehab 542d966dc65SMauro Carvalho Chehab # Ignore an empty return type (It's a macro) 543d966dc65SMauro Carvalho Chehab # Ignore functions with a "void" return type (but not "void *") 54404a383ceSMauro Carvalho Chehab if not return_type or KernRe(r'void\s*\w*\s*$').search(return_type): 545d966dc65SMauro Carvalho Chehab return 546d966dc65SMauro Carvalho Chehab 547d966dc65SMauro Carvalho Chehab if not self.entry.sections.get("Return", None): 548*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 549d966dc65SMauro Carvalho Chehab f"No description found for return value of '{declaration_name}'") 550d966dc65SMauro Carvalho Chehab 551d966dc65SMauro Carvalho Chehab def dump_struct(self, ln, proto): 552d966dc65SMauro Carvalho Chehab """ 553d966dc65SMauro Carvalho Chehab Store an entry for an struct or union 554d966dc65SMauro Carvalho Chehab """ 555d966dc65SMauro Carvalho Chehab 556d966dc65SMauro Carvalho Chehab type_pattern = r'(struct|union)' 557d966dc65SMauro Carvalho Chehab 558d966dc65SMauro Carvalho Chehab qualifiers = [ 559d966dc65SMauro Carvalho Chehab "__attribute__", 560d966dc65SMauro Carvalho Chehab "__packed", 561d966dc65SMauro Carvalho Chehab "__aligned", 562d966dc65SMauro Carvalho Chehab "____cacheline_aligned_in_smp", 563d966dc65SMauro Carvalho Chehab "____cacheline_aligned", 564d966dc65SMauro Carvalho Chehab ] 565d966dc65SMauro Carvalho Chehab 566d966dc65SMauro Carvalho Chehab definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?" 56704a383ceSMauro Carvalho Chehab struct_members = KernRe(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)') 568d966dc65SMauro Carvalho Chehab 569d966dc65SMauro Carvalho Chehab # Extract struct/union definition 570d966dc65SMauro Carvalho Chehab members = None 571d966dc65SMauro Carvalho Chehab declaration_name = None 572d966dc65SMauro Carvalho Chehab decl_type = None 573d966dc65SMauro Carvalho Chehab 57404a383ceSMauro Carvalho Chehab r = KernRe(type_pattern + r'\s+(\w+)\s*' + definition_body) 575d966dc65SMauro Carvalho Chehab if r.search(proto): 576d966dc65SMauro Carvalho Chehab decl_type = r.group(1) 577d966dc65SMauro Carvalho Chehab declaration_name = r.group(2) 578d966dc65SMauro Carvalho Chehab members = r.group(3) 579d966dc65SMauro Carvalho Chehab else: 58004a383ceSMauro Carvalho Chehab r = KernRe(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;') 581d966dc65SMauro Carvalho Chehab 582d966dc65SMauro Carvalho Chehab if r.search(proto): 583d966dc65SMauro Carvalho Chehab decl_type = r.group(1) 584d966dc65SMauro Carvalho Chehab declaration_name = r.group(3) 585d966dc65SMauro Carvalho Chehab members = r.group(2) 586d966dc65SMauro Carvalho Chehab 587d966dc65SMauro Carvalho Chehab if not members: 588*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") 589d966dc65SMauro Carvalho Chehab return 590d966dc65SMauro Carvalho Chehab 591d966dc65SMauro Carvalho Chehab if self.entry.identifier != declaration_name: 592*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 593d966dc65SMauro Carvalho Chehab f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n") 594d966dc65SMauro Carvalho Chehab return 595d966dc65SMauro Carvalho Chehab 596d966dc65SMauro Carvalho Chehab args_pattern = r'([^,)]+)' 597d966dc65SMauro Carvalho Chehab 598d966dc65SMauro Carvalho Chehab sub_prefixes = [ 59904a383ceSMauro Carvalho Chehab (KernRe(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''), 60004a383ceSMauro Carvalho Chehab (KernRe(r'\/\*\s*private:.*', re.S | re.I), ''), 601d966dc65SMauro Carvalho Chehab 602d966dc65SMauro Carvalho Chehab # Strip comments 60304a383ceSMauro Carvalho Chehab (KernRe(r'\/\*.*?\*\/', re.S), ''), 604d966dc65SMauro Carvalho Chehab 605d966dc65SMauro Carvalho Chehab # Strip attributes 606d966dc65SMauro Carvalho Chehab (attribute, ' '), 60704a383ceSMauro Carvalho Chehab (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), 60804a383ceSMauro Carvalho Chehab (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '), 60904a383ceSMauro Carvalho Chehab (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '), 61004a383ceSMauro Carvalho Chehab (KernRe(r'\s*__packed\s*', re.S), ' '), 61104a383ceSMauro Carvalho Chehab (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '), 61204a383ceSMauro Carvalho Chehab (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '), 61304a383ceSMauro Carvalho Chehab (KernRe(r'\s*____cacheline_aligned', re.S), ' '), 614d966dc65SMauro Carvalho Chehab 615d966dc65SMauro Carvalho Chehab # Unwrap struct_group macros based on this definition: 616d966dc65SMauro Carvalho Chehab # __struct_group(TAG, NAME, ATTRS, MEMBERS...) 617d966dc65SMauro Carvalho Chehab # which has variants like: struct_group(NAME, MEMBERS...) 618d966dc65SMauro Carvalho Chehab # Only MEMBERS arguments require documentation. 619d966dc65SMauro Carvalho Chehab # 620d966dc65SMauro Carvalho Chehab # Parsing them happens on two steps: 621d966dc65SMauro Carvalho Chehab # 622d966dc65SMauro Carvalho Chehab # 1. drop struct group arguments that aren't at MEMBERS, 623d966dc65SMauro Carvalho Chehab # storing them as STRUCT_GROUP(MEMBERS) 624d966dc65SMauro Carvalho Chehab # 625d966dc65SMauro Carvalho Chehab # 2. remove STRUCT_GROUP() ancillary macro. 626d966dc65SMauro Carvalho Chehab # 627d966dc65SMauro Carvalho Chehab # The original logic used to remove STRUCT_GROUP() using an 628d966dc65SMauro Carvalho Chehab # advanced regex: 629d966dc65SMauro Carvalho Chehab # 630d966dc65SMauro Carvalho Chehab # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*; 631d966dc65SMauro Carvalho Chehab # 632d966dc65SMauro Carvalho Chehab # with two patterns that are incompatible with 633d966dc65SMauro Carvalho Chehab # Python re module, as it has: 634d966dc65SMauro Carvalho Chehab # 635d966dc65SMauro Carvalho Chehab # - a recursive pattern: (?1) 636d966dc65SMauro Carvalho Chehab # - an atomic grouping: (?>...) 637d966dc65SMauro Carvalho Chehab # 638d966dc65SMauro Carvalho Chehab # I tried a simpler version: but it didn't work either: 639d966dc65SMauro Carvalho Chehab # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*; 640d966dc65SMauro Carvalho Chehab # 641d966dc65SMauro Carvalho Chehab # As it doesn't properly match the end parenthesis on some cases. 642d966dc65SMauro Carvalho Chehab # 643d966dc65SMauro Carvalho Chehab # So, a better solution was crafted: there's now a NestedMatch 644d966dc65SMauro Carvalho Chehab # class that ensures that delimiters after a search are properly 645d966dc65SMauro Carvalho Chehab # matched. So, the implementation to drop STRUCT_GROUP() will be 646d966dc65SMauro Carvalho Chehab # handled in separate. 647d966dc65SMauro Carvalho Chehab 64804a383ceSMauro Carvalho Chehab (KernRe(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('), 64904a383ceSMauro Carvalho Chehab (KernRe(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('), 65004a383ceSMauro Carvalho Chehab (KernRe(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('), 65104a383ceSMauro Carvalho Chehab (KernRe(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('), 652d966dc65SMauro Carvalho Chehab 653d966dc65SMauro Carvalho Chehab # Replace macros 654d966dc65SMauro Carvalho Chehab # 655485f6f79SMauro Carvalho Chehab # TODO: use NestedMatch for FOO($1, $2, ...) matches 656485f6f79SMauro Carvalho Chehab # 657485f6f79SMauro Carvalho Chehab # it is better to also move those to the NestedMatch logic, 658d966dc65SMauro Carvalho Chehab # to ensure that parenthesis will be properly matched. 659d966dc65SMauro Carvalho Chehab 66004a383ceSMauro Carvalho Chehab (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'), 66104a383ceSMauro Carvalho Chehab (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'), 66204a383ceSMauro Carvalho Chehab (KernRe(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'), 66304a383ceSMauro Carvalho Chehab (KernRe(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'), 66404a383ceSMauro Carvalho Chehab (KernRe(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'), 66504a383ceSMauro Carvalho Chehab (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'), 66604a383ceSMauro Carvalho Chehab (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'), 66704a383ceSMauro Carvalho Chehab (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'), 66804a383ceSMauro Carvalho Chehab (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'), 669d966dc65SMauro Carvalho Chehab ] 670d966dc65SMauro Carvalho Chehab 671d966dc65SMauro Carvalho Chehab # Regexes here are guaranteed to have the end limiter matching 672d966dc65SMauro Carvalho Chehab # the start delimiter. Yet, right now, only one replace group 673d966dc65SMauro Carvalho Chehab # is allowed. 674d966dc65SMauro Carvalho Chehab 675d966dc65SMauro Carvalho Chehab sub_nested_prefixes = [ 676d966dc65SMauro Carvalho Chehab (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), 677d966dc65SMauro Carvalho Chehab ] 678d966dc65SMauro Carvalho Chehab 679d966dc65SMauro Carvalho Chehab for search, sub in sub_prefixes: 680d966dc65SMauro Carvalho Chehab members = search.sub(sub, members) 681d966dc65SMauro Carvalho Chehab 682d966dc65SMauro Carvalho Chehab nested = NestedMatch() 683d966dc65SMauro Carvalho Chehab 684d966dc65SMauro Carvalho Chehab for search, sub in sub_nested_prefixes: 685d966dc65SMauro Carvalho Chehab members = nested.sub(search, sub, members) 686d966dc65SMauro Carvalho Chehab 687d966dc65SMauro Carvalho Chehab # Keeps the original declaration as-is 688d966dc65SMauro Carvalho Chehab declaration = members 689d966dc65SMauro Carvalho Chehab 690d966dc65SMauro Carvalho Chehab # Split nested struct/union elements 691d966dc65SMauro Carvalho Chehab # 692d966dc65SMauro Carvalho Chehab # This loop was simpler at the original kernel-doc perl version, as 693d966dc65SMauro Carvalho Chehab # while ($members =~ m/$struct_members/) { ... } 694d966dc65SMauro Carvalho Chehab # reads 'members' string on each interaction. 695d966dc65SMauro Carvalho Chehab # 696d966dc65SMauro Carvalho Chehab # Python behavior is different: it parses 'members' only once, 697d966dc65SMauro Carvalho Chehab # creating a list of tuples from the first interaction. 698d966dc65SMauro Carvalho Chehab # 699d966dc65SMauro Carvalho Chehab # On other words, this won't get nested structs. 700d966dc65SMauro Carvalho Chehab # 701d966dc65SMauro Carvalho Chehab # So, we need to have an extra loop on Python to override such 702d966dc65SMauro Carvalho Chehab # re limitation. 703d966dc65SMauro Carvalho Chehab 704d966dc65SMauro Carvalho Chehab while True: 705d966dc65SMauro Carvalho Chehab tuples = struct_members.findall(members) 706d966dc65SMauro Carvalho Chehab if not tuples: 707d966dc65SMauro Carvalho Chehab break 708d966dc65SMauro Carvalho Chehab 709d966dc65SMauro Carvalho Chehab for t in tuples: 710d966dc65SMauro Carvalho Chehab newmember = "" 711d966dc65SMauro Carvalho Chehab maintype = t[0] 712d966dc65SMauro Carvalho Chehab s_ids = t[5] 713d966dc65SMauro Carvalho Chehab content = t[3] 714d966dc65SMauro Carvalho Chehab 715d966dc65SMauro Carvalho Chehab oldmember = "".join(t) 716d966dc65SMauro Carvalho Chehab 717d966dc65SMauro Carvalho Chehab for s_id in s_ids.split(','): 718d966dc65SMauro Carvalho Chehab s_id = s_id.strip() 719d966dc65SMauro Carvalho Chehab 720d966dc65SMauro Carvalho Chehab newmember += f"{maintype} {s_id}; " 72104a383ceSMauro Carvalho Chehab s_id = KernRe(r'[:\[].*').sub('', s_id) 72204a383ceSMauro Carvalho Chehab s_id = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', s_id) 723d966dc65SMauro Carvalho Chehab 724d966dc65SMauro Carvalho Chehab for arg in content.split(';'): 725d966dc65SMauro Carvalho Chehab arg = arg.strip() 726d966dc65SMauro Carvalho Chehab 727d966dc65SMauro Carvalho Chehab if not arg: 728d966dc65SMauro Carvalho Chehab continue 729d966dc65SMauro Carvalho Chehab 73004a383ceSMauro Carvalho Chehab r = KernRe(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)') 731d966dc65SMauro Carvalho Chehab if r.match(arg): 732d966dc65SMauro Carvalho Chehab # Pointer-to-function 733d966dc65SMauro Carvalho Chehab dtype = r.group(1) 734d966dc65SMauro Carvalho Chehab name = r.group(2) 735d966dc65SMauro Carvalho Chehab extra = r.group(3) 736d966dc65SMauro Carvalho Chehab 737d966dc65SMauro Carvalho Chehab if not name: 738d966dc65SMauro Carvalho Chehab continue 739d966dc65SMauro Carvalho Chehab 740d966dc65SMauro Carvalho Chehab if not s_id: 741d966dc65SMauro Carvalho Chehab # Anonymous struct/union 742d966dc65SMauro Carvalho Chehab newmember += f"{dtype}{name}{extra}; " 743d966dc65SMauro Carvalho Chehab else: 744d966dc65SMauro Carvalho Chehab newmember += f"{dtype}{s_id}.{name}{extra}; " 745d966dc65SMauro Carvalho Chehab 746d966dc65SMauro Carvalho Chehab else: 747d966dc65SMauro Carvalho Chehab arg = arg.strip() 748d966dc65SMauro Carvalho Chehab # Handle bitmaps 74904a383ceSMauro Carvalho Chehab arg = KernRe(r':\s*\d+\s*').sub('', arg) 750d966dc65SMauro Carvalho Chehab 751d966dc65SMauro Carvalho Chehab # Handle arrays 75204a383ceSMauro Carvalho Chehab arg = KernRe(r'\[.*\]').sub('', arg) 753d966dc65SMauro Carvalho Chehab 754d966dc65SMauro Carvalho Chehab # Handle multiple IDs 75504a383ceSMauro Carvalho Chehab arg = KernRe(r'\s*,\s*').sub(',', arg) 756d966dc65SMauro Carvalho Chehab 75704a383ceSMauro Carvalho Chehab r = KernRe(r'(.*)\s+([\S+,]+)') 758d966dc65SMauro Carvalho Chehab 759d966dc65SMauro Carvalho Chehab if r.search(arg): 760d966dc65SMauro Carvalho Chehab dtype = r.group(1) 761d966dc65SMauro Carvalho Chehab names = r.group(2) 762d966dc65SMauro Carvalho Chehab else: 763d966dc65SMauro Carvalho Chehab newmember += f"{arg}; " 764d966dc65SMauro Carvalho Chehab continue 765d966dc65SMauro Carvalho Chehab 766d966dc65SMauro Carvalho Chehab for name in names.split(','): 76704a383ceSMauro Carvalho Chehab name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip() 768d966dc65SMauro Carvalho Chehab 769d966dc65SMauro Carvalho Chehab if not name: 770d966dc65SMauro Carvalho Chehab continue 771d966dc65SMauro Carvalho Chehab 772d966dc65SMauro Carvalho Chehab if not s_id: 773d966dc65SMauro Carvalho Chehab # Anonymous struct/union 774d966dc65SMauro Carvalho Chehab newmember += f"{dtype} {name}; " 775d966dc65SMauro Carvalho Chehab else: 776d966dc65SMauro Carvalho Chehab newmember += f"{dtype} {s_id}.{name}; " 777d966dc65SMauro Carvalho Chehab 778d966dc65SMauro Carvalho Chehab members = members.replace(oldmember, newmember) 779d966dc65SMauro Carvalho Chehab 780d966dc65SMauro Carvalho Chehab # Ignore other nested elements, like enums 781d966dc65SMauro Carvalho Chehab members = re.sub(r'(\{[^\{\}]*\})', '', members) 782d966dc65SMauro Carvalho Chehab 783d966dc65SMauro Carvalho Chehab self.create_parameter_list(ln, decl_type, members, ';', 784d966dc65SMauro Carvalho Chehab declaration_name) 785d966dc65SMauro Carvalho Chehab self.check_sections(ln, declaration_name, decl_type, 786d966dc65SMauro Carvalho Chehab self.entry.sectcheck, self.entry.struct_actual) 787d966dc65SMauro Carvalho Chehab 788d966dc65SMauro Carvalho Chehab # Adjust declaration for better display 78904a383ceSMauro Carvalho Chehab declaration = KernRe(r'([\{;])').sub(r'\1\n', declaration) 79004a383ceSMauro Carvalho Chehab declaration = KernRe(r'\}\s+;').sub('};', declaration) 791d966dc65SMauro Carvalho Chehab 792d966dc65SMauro Carvalho Chehab # Better handle inlined enums 793d966dc65SMauro Carvalho Chehab while True: 79404a383ceSMauro Carvalho Chehab r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') 795d966dc65SMauro Carvalho Chehab if not r.search(declaration): 796d966dc65SMauro Carvalho Chehab break 797d966dc65SMauro Carvalho Chehab 798d966dc65SMauro Carvalho Chehab declaration = r.sub(r'\1,\n\2', declaration) 799d966dc65SMauro Carvalho Chehab 800d966dc65SMauro Carvalho Chehab def_args = declaration.split('\n') 801d966dc65SMauro Carvalho Chehab level = 1 802d966dc65SMauro Carvalho Chehab declaration = "" 803d966dc65SMauro Carvalho Chehab for clause in def_args: 804d966dc65SMauro Carvalho Chehab 805d966dc65SMauro Carvalho Chehab clause = clause.strip() 80604a383ceSMauro Carvalho Chehab clause = KernRe(r'\s+').sub(' ', clause, count=1) 807d966dc65SMauro Carvalho Chehab 808d966dc65SMauro Carvalho Chehab if not clause: 809d966dc65SMauro Carvalho Chehab continue 810d966dc65SMauro Carvalho Chehab 811d966dc65SMauro Carvalho Chehab if '}' in clause and level > 1: 812d966dc65SMauro Carvalho Chehab level -= 1 813d966dc65SMauro Carvalho Chehab 81404a383ceSMauro Carvalho Chehab if not KernRe(r'^\s*#').match(clause): 815d966dc65SMauro Carvalho Chehab declaration += "\t" * level 816d966dc65SMauro Carvalho Chehab 817d966dc65SMauro Carvalho Chehab declaration += "\t" + clause + "\n" 818d966dc65SMauro Carvalho Chehab if "{" in clause and "}" not in clause: 819d966dc65SMauro Carvalho Chehab level += 1 820d966dc65SMauro Carvalho Chehab 821d966dc65SMauro Carvalho Chehab self.output_declaration(decl_type, declaration_name, 822d966dc65SMauro Carvalho Chehab struct=declaration_name, 823d966dc65SMauro Carvalho Chehab definition=declaration, 824d966dc65SMauro Carvalho Chehab parameterlist=self.entry.parameterlist, 825d966dc65SMauro Carvalho Chehab parameterdescs=self.entry.parameterdescs, 826d966dc65SMauro Carvalho Chehab parametertypes=self.entry.parametertypes, 827c3597ab2SMauro Carvalho Chehab parameterdesc_start_lines=self.entry.parameterdesc_start_lines, 828d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 829d966dc65SMauro Carvalho Chehab sections=self.entry.sections, 830c3597ab2SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines, 831d966dc65SMauro Carvalho Chehab purpose=self.entry.declaration_purpose) 832d966dc65SMauro Carvalho Chehab 833d966dc65SMauro Carvalho Chehab def dump_enum(self, ln, proto): 834d966dc65SMauro Carvalho Chehab """ 835d966dc65SMauro Carvalho Chehab Stores an enum inside self.entries array. 836d966dc65SMauro Carvalho Chehab """ 837d966dc65SMauro Carvalho Chehab 838d966dc65SMauro Carvalho Chehab # Ignore members marked private 83904a383ceSMauro Carvalho Chehab proto = KernRe(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto) 84004a383ceSMauro Carvalho Chehab proto = KernRe(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto) 841d966dc65SMauro Carvalho Chehab 842d966dc65SMauro Carvalho Chehab # Strip comments 84304a383ceSMauro Carvalho Chehab proto = KernRe(r'\/\*.*?\*\/', flags=re.S).sub('', proto) 844d966dc65SMauro Carvalho Chehab 845d966dc65SMauro Carvalho Chehab # Strip #define macros inside enums 84604a383ceSMauro Carvalho Chehab proto = KernRe(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto) 847d966dc65SMauro Carvalho Chehab 848d966dc65SMauro Carvalho Chehab members = None 849d966dc65SMauro Carvalho Chehab declaration_name = None 850d966dc65SMauro Carvalho Chehab 85104a383ceSMauro Carvalho Chehab r = KernRe(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;') 852d966dc65SMauro Carvalho Chehab if r.search(proto): 853d966dc65SMauro Carvalho Chehab declaration_name = r.group(2) 854d966dc65SMauro Carvalho Chehab members = r.group(1).rstrip() 855d966dc65SMauro Carvalho Chehab else: 85604a383ceSMauro Carvalho Chehab r = KernRe(r'enum\s+(\w*)\s*\{(.*)\}') 857d966dc65SMauro Carvalho Chehab if r.match(proto): 858d966dc65SMauro Carvalho Chehab declaration_name = r.group(1) 859d966dc65SMauro Carvalho Chehab members = r.group(2).rstrip() 860d966dc65SMauro Carvalho Chehab 861d966dc65SMauro Carvalho Chehab if not members: 862*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"{proto}: error: Cannot parse enum!") 863d966dc65SMauro Carvalho Chehab return 864d966dc65SMauro Carvalho Chehab 865d966dc65SMauro Carvalho Chehab if self.entry.identifier != declaration_name: 866d966dc65SMauro Carvalho Chehab if self.entry.identifier == "": 867*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 868d966dc65SMauro Carvalho Chehab f"{proto}: wrong kernel-doc identifier on prototype") 869d966dc65SMauro Carvalho Chehab else: 870*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 871d966dc65SMauro Carvalho Chehab f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead") 872d966dc65SMauro Carvalho Chehab return 873d966dc65SMauro Carvalho Chehab 874d966dc65SMauro Carvalho Chehab if not declaration_name: 875d966dc65SMauro Carvalho Chehab declaration_name = "(anonymous)" 876d966dc65SMauro Carvalho Chehab 877d966dc65SMauro Carvalho Chehab member_set = set() 878d966dc65SMauro Carvalho Chehab 87904a383ceSMauro Carvalho Chehab members = KernRe(r'\([^;]*?[\)]').sub('', members) 880d966dc65SMauro Carvalho Chehab 881d966dc65SMauro Carvalho Chehab for arg in members.split(','): 882d966dc65SMauro Carvalho Chehab if not arg: 883d966dc65SMauro Carvalho Chehab continue 88404a383ceSMauro Carvalho Chehab arg = KernRe(r'^\s*(\w+).*').sub(r'\1', arg) 885d966dc65SMauro Carvalho Chehab self.entry.parameterlist.append(arg) 886d966dc65SMauro Carvalho Chehab if arg not in self.entry.parameterdescs: 887d966dc65SMauro Carvalho Chehab self.entry.parameterdescs[arg] = self.undescribed 888*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 889d966dc65SMauro Carvalho Chehab f"Enum value '{arg}' not described in enum '{declaration_name}'") 890d966dc65SMauro Carvalho Chehab member_set.add(arg) 891d966dc65SMauro Carvalho Chehab 892d966dc65SMauro Carvalho Chehab for k in self.entry.parameterdescs: 893d966dc65SMauro Carvalho Chehab if k not in member_set: 894*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 895d966dc65SMauro Carvalho Chehab f"Excess enum value '%{k}' description in '{declaration_name}'") 896d966dc65SMauro Carvalho Chehab 897d966dc65SMauro Carvalho Chehab self.output_declaration('enum', declaration_name, 898d966dc65SMauro Carvalho Chehab enum=declaration_name, 899d966dc65SMauro Carvalho Chehab parameterlist=self.entry.parameterlist, 900d966dc65SMauro Carvalho Chehab parameterdescs=self.entry.parameterdescs, 901c3597ab2SMauro Carvalho Chehab parameterdesc_start_lines=self.entry.parameterdesc_start_lines, 902d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 903d966dc65SMauro Carvalho Chehab sections=self.entry.sections, 904c3597ab2SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines, 905d966dc65SMauro Carvalho Chehab purpose=self.entry.declaration_purpose) 906d966dc65SMauro Carvalho Chehab 907d966dc65SMauro Carvalho Chehab def dump_declaration(self, ln, prototype): 908d966dc65SMauro Carvalho Chehab """ 909d966dc65SMauro Carvalho Chehab Stores a data declaration inside self.entries array. 910d966dc65SMauro Carvalho Chehab """ 911d966dc65SMauro Carvalho Chehab 912d966dc65SMauro Carvalho Chehab if self.entry.decl_type == "enum": 913d966dc65SMauro Carvalho Chehab self.dump_enum(ln, prototype) 914d966dc65SMauro Carvalho Chehab return 915d966dc65SMauro Carvalho Chehab 916d966dc65SMauro Carvalho Chehab if self.entry.decl_type == "typedef": 917d966dc65SMauro Carvalho Chehab self.dump_typedef(ln, prototype) 918d966dc65SMauro Carvalho Chehab return 919d966dc65SMauro Carvalho Chehab 920d966dc65SMauro Carvalho Chehab if self.entry.decl_type in ["union", "struct"]: 921d966dc65SMauro Carvalho Chehab self.dump_struct(ln, prototype) 922d966dc65SMauro Carvalho Chehab return 923d966dc65SMauro Carvalho Chehab 924d966dc65SMauro Carvalho Chehab self.output_declaration(self.entry.decl_type, prototype, 925d966dc65SMauro Carvalho Chehab entry=self.entry) 926d966dc65SMauro Carvalho Chehab 927d966dc65SMauro Carvalho Chehab def dump_function(self, ln, prototype): 928d966dc65SMauro Carvalho Chehab """ 929d966dc65SMauro Carvalho Chehab Stores a function of function macro inside self.entries array. 930d966dc65SMauro Carvalho Chehab """ 931d966dc65SMauro Carvalho Chehab 932d966dc65SMauro Carvalho Chehab func_macro = False 933d966dc65SMauro Carvalho Chehab return_type = '' 934d966dc65SMauro Carvalho Chehab decl_type = 'function' 935d966dc65SMauro Carvalho Chehab 936d966dc65SMauro Carvalho Chehab # Prefixes that would be removed 937d966dc65SMauro Carvalho Chehab sub_prefixes = [ 938d966dc65SMauro Carvalho Chehab (r"^static +", "", 0), 939d966dc65SMauro Carvalho Chehab (r"^extern +", "", 0), 940d966dc65SMauro Carvalho Chehab (r"^asmlinkage +", "", 0), 941d966dc65SMauro Carvalho Chehab (r"^inline +", "", 0), 942d966dc65SMauro Carvalho Chehab (r"^__inline__ +", "", 0), 943d966dc65SMauro Carvalho Chehab (r"^__inline +", "", 0), 944d966dc65SMauro Carvalho Chehab (r"^__always_inline +", "", 0), 945d966dc65SMauro Carvalho Chehab (r"^noinline +", "", 0), 946d966dc65SMauro Carvalho Chehab (r"^__FORTIFY_INLINE +", "", 0), 947d966dc65SMauro Carvalho Chehab (r"__init +", "", 0), 948d966dc65SMauro Carvalho Chehab (r"__init_or_module +", "", 0), 949d966dc65SMauro Carvalho Chehab (r"__deprecated +", "", 0), 950d966dc65SMauro Carvalho Chehab (r"__flatten +", "", 0), 951d966dc65SMauro Carvalho Chehab (r"__meminit +", "", 0), 952d966dc65SMauro Carvalho Chehab (r"__must_check +", "", 0), 953d966dc65SMauro Carvalho Chehab (r"__weak +", "", 0), 954d966dc65SMauro Carvalho Chehab (r"__sched +", "", 0), 955d966dc65SMauro Carvalho Chehab (r"_noprof", "", 0), 956d966dc65SMauro Carvalho Chehab (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0), 957d966dc65SMauro Carvalho Chehab (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0), 958d966dc65SMauro Carvalho Chehab (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0), 959d966dc65SMauro Carvalho Chehab (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0), 960d966dc65SMauro Carvalho Chehab (r"__attribute_const__ +", "", 0), 961d966dc65SMauro Carvalho Chehab 962d966dc65SMauro Carvalho Chehab # It seems that Python support for re.X is broken: 963d966dc65SMauro Carvalho Chehab # At least for me (Python 3.13), this didn't work 964d966dc65SMauro Carvalho Chehab# (r""" 965d966dc65SMauro Carvalho Chehab# __attribute__\s*\(\( 966d966dc65SMauro Carvalho Chehab# (?: 967d966dc65SMauro Carvalho Chehab# [\w\s]+ # attribute name 968d966dc65SMauro Carvalho Chehab# (?:\([^)]*\))? # attribute arguments 969d966dc65SMauro Carvalho Chehab# \s*,? # optional comma at the end 970d966dc65SMauro Carvalho Chehab# )+ 971d966dc65SMauro Carvalho Chehab# \)\)\s+ 972d966dc65SMauro Carvalho Chehab# """, "", re.X), 973d966dc65SMauro Carvalho Chehab 974d966dc65SMauro Carvalho Chehab # So, remove whitespaces and comments from it 975d966dc65SMauro Carvalho Chehab (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0), 976d966dc65SMauro Carvalho Chehab ] 977d966dc65SMauro Carvalho Chehab 978d966dc65SMauro Carvalho Chehab for search, sub, flags in sub_prefixes: 97904a383ceSMauro Carvalho Chehab prototype = KernRe(search, flags).sub(sub, prototype) 980d966dc65SMauro Carvalho Chehab 981d966dc65SMauro Carvalho Chehab # Macros are a special case, as they change the prototype format 98204a383ceSMauro Carvalho Chehab new_proto = KernRe(r"^#\s*define\s+").sub("", prototype) 983d966dc65SMauro Carvalho Chehab if new_proto != prototype: 984d966dc65SMauro Carvalho Chehab is_define_proto = True 985d966dc65SMauro Carvalho Chehab prototype = new_proto 986d966dc65SMauro Carvalho Chehab else: 987d966dc65SMauro Carvalho Chehab is_define_proto = False 988d966dc65SMauro Carvalho Chehab 989d966dc65SMauro Carvalho Chehab # Yes, this truly is vile. We are looking for: 990d966dc65SMauro Carvalho Chehab # 1. Return type (may be nothing if we're looking at a macro) 991d966dc65SMauro Carvalho Chehab # 2. Function name 992d966dc65SMauro Carvalho Chehab # 3. Function parameters. 993d966dc65SMauro Carvalho Chehab # 994d966dc65SMauro Carvalho Chehab # All the while we have to watch out for function pointer parameters 995d966dc65SMauro Carvalho Chehab # (which IIRC is what the two sections are for), C types (these 996d966dc65SMauro Carvalho Chehab # regexps don't even start to express all the possibilities), and 997d966dc65SMauro Carvalho Chehab # so on. 998d966dc65SMauro Carvalho Chehab # 999d966dc65SMauro Carvalho Chehab # If you mess with these regexps, it's a good idea to check that 1000d966dc65SMauro Carvalho Chehab # the following functions' documentation still comes out right: 1001d966dc65SMauro Carvalho Chehab # - parport_register_device (function pointer parameters) 1002d966dc65SMauro Carvalho Chehab # - atomic_set (macro) 1003d966dc65SMauro Carvalho Chehab # - pci_match_device, __copy_to_user (long return type) 1004d966dc65SMauro Carvalho Chehab 1005d966dc65SMauro Carvalho Chehab name = r'[a-zA-Z0-9_~:]+' 1006d966dc65SMauro Carvalho Chehab prototype_end1 = r'[^\(]*' 1007d966dc65SMauro Carvalho Chehab prototype_end2 = r'[^\{]*' 1008d966dc65SMauro Carvalho Chehab prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)' 1009d966dc65SMauro Carvalho Chehab 1010d966dc65SMauro Carvalho Chehab # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group. 1011d966dc65SMauro Carvalho Chehab # So, this needs to be mapped in Python with (?:...)? or (?:...)+ 1012d966dc65SMauro Carvalho Chehab 1013d966dc65SMauro Carvalho Chehab type1 = r'(?:[\w\s]+)?' 1014d966dc65SMauro Carvalho Chehab type2 = r'(?:[\w\s]+\*+)+' 1015d966dc65SMauro Carvalho Chehab 1016d966dc65SMauro Carvalho Chehab found = False 1017d966dc65SMauro Carvalho Chehab 1018d966dc65SMauro Carvalho Chehab if is_define_proto: 101904a383ceSMauro Carvalho Chehab r = KernRe(r'^()(' + name + r')\s+') 1020d966dc65SMauro Carvalho Chehab 1021d966dc65SMauro Carvalho Chehab if r.search(prototype): 1022d966dc65SMauro Carvalho Chehab return_type = '' 1023d966dc65SMauro Carvalho Chehab declaration_name = r.group(2) 1024d966dc65SMauro Carvalho Chehab func_macro = True 1025d966dc65SMauro Carvalho Chehab 1026d966dc65SMauro Carvalho Chehab found = True 1027d966dc65SMauro Carvalho Chehab 1028d966dc65SMauro Carvalho Chehab if not found: 1029d966dc65SMauro Carvalho Chehab patterns = [ 1030d966dc65SMauro Carvalho Chehab rf'^()({name})\s*{prototype_end}', 1031d966dc65SMauro Carvalho Chehab rf'^({type1})\s+({name})\s*{prototype_end}', 1032d966dc65SMauro Carvalho Chehab rf'^({type2})\s*({name})\s*{prototype_end}', 1033d966dc65SMauro Carvalho Chehab ] 1034d966dc65SMauro Carvalho Chehab 1035d966dc65SMauro Carvalho Chehab for p in patterns: 103604a383ceSMauro Carvalho Chehab r = KernRe(p) 1037d966dc65SMauro Carvalho Chehab 1038d966dc65SMauro Carvalho Chehab if r.match(prototype): 1039d966dc65SMauro Carvalho Chehab 1040d966dc65SMauro Carvalho Chehab return_type = r.group(1) 1041d966dc65SMauro Carvalho Chehab declaration_name = r.group(2) 1042d966dc65SMauro Carvalho Chehab args = r.group(3) 1043d966dc65SMauro Carvalho Chehab 1044d966dc65SMauro Carvalho Chehab self.create_parameter_list(ln, decl_type, args, ',', 1045d966dc65SMauro Carvalho Chehab declaration_name) 1046d966dc65SMauro Carvalho Chehab 1047d966dc65SMauro Carvalho Chehab found = True 1048d966dc65SMauro Carvalho Chehab break 1049d966dc65SMauro Carvalho Chehab if not found: 1050*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1051d966dc65SMauro Carvalho Chehab f"cannot understand function prototype: '{prototype}'") 1052d966dc65SMauro Carvalho Chehab return 1053d966dc65SMauro Carvalho Chehab 1054d966dc65SMauro Carvalho Chehab if self.entry.identifier != declaration_name: 1055*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1056d966dc65SMauro Carvalho Chehab f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead") 1057d966dc65SMauro Carvalho Chehab return 1058d966dc65SMauro Carvalho Chehab 1059d966dc65SMauro Carvalho Chehab prms = " ".join(self.entry.parameterlist) 1060d966dc65SMauro Carvalho Chehab self.check_sections(ln, declaration_name, "function", 1061d966dc65SMauro Carvalho Chehab self.entry.sectcheck, prms) 1062d966dc65SMauro Carvalho Chehab 1063d966dc65SMauro Carvalho Chehab self.check_return_section(ln, declaration_name, return_type) 1064d966dc65SMauro Carvalho Chehab 1065d966dc65SMauro Carvalho Chehab if 'typedef' in return_type: 1066d966dc65SMauro Carvalho Chehab self.output_declaration(decl_type, declaration_name, 1067d966dc65SMauro Carvalho Chehab function=declaration_name, 1068d966dc65SMauro Carvalho Chehab typedef=True, 1069d966dc65SMauro Carvalho Chehab functiontype=return_type, 1070d966dc65SMauro Carvalho Chehab parameterlist=self.entry.parameterlist, 1071d966dc65SMauro Carvalho Chehab parameterdescs=self.entry.parameterdescs, 1072d966dc65SMauro Carvalho Chehab parametertypes=self.entry.parametertypes, 1073c3597ab2SMauro Carvalho Chehab parameterdesc_start_lines=self.entry.parameterdesc_start_lines, 1074d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 1075d966dc65SMauro Carvalho Chehab sections=self.entry.sections, 1076c3597ab2SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines, 1077d966dc65SMauro Carvalho Chehab purpose=self.entry.declaration_purpose, 1078d966dc65SMauro Carvalho Chehab func_macro=func_macro) 1079d966dc65SMauro Carvalho Chehab else: 1080d966dc65SMauro Carvalho Chehab self.output_declaration(decl_type, declaration_name, 1081d966dc65SMauro Carvalho Chehab function=declaration_name, 1082d966dc65SMauro Carvalho Chehab typedef=False, 1083d966dc65SMauro Carvalho Chehab functiontype=return_type, 1084d966dc65SMauro Carvalho Chehab parameterlist=self.entry.parameterlist, 1085d966dc65SMauro Carvalho Chehab parameterdescs=self.entry.parameterdescs, 1086d966dc65SMauro Carvalho Chehab parametertypes=self.entry.parametertypes, 1087c3597ab2SMauro Carvalho Chehab parameterdesc_start_lines=self.entry.parameterdesc_start_lines, 1088d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 1089d966dc65SMauro Carvalho Chehab sections=self.entry.sections, 1090c3597ab2SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines, 1091d966dc65SMauro Carvalho Chehab purpose=self.entry.declaration_purpose, 1092d966dc65SMauro Carvalho Chehab func_macro=func_macro) 1093d966dc65SMauro Carvalho Chehab 1094d966dc65SMauro Carvalho Chehab def dump_typedef(self, ln, proto): 1095d966dc65SMauro Carvalho Chehab """ 1096d966dc65SMauro Carvalho Chehab Stores a typedef inside self.entries array. 1097d966dc65SMauro Carvalho Chehab """ 1098d966dc65SMauro Carvalho Chehab 1099de258fa8SSean Anderson typedef_type = r'((?:\s+[\w\*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' 1100d966dc65SMauro Carvalho Chehab typedef_ident = r'\*?\s*(\w\S+)\s*' 1101d966dc65SMauro Carvalho Chehab typedef_args = r'\s*\((.*)\);' 1102d966dc65SMauro Carvalho Chehab 110304a383ceSMauro Carvalho Chehab typedef1 = KernRe(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args) 110404a383ceSMauro Carvalho Chehab typedef2 = KernRe(r'typedef' + typedef_type + typedef_ident + typedef_args) 1105d966dc65SMauro Carvalho Chehab 1106d966dc65SMauro Carvalho Chehab # Strip comments 110704a383ceSMauro Carvalho Chehab proto = KernRe(r'/\*.*?\*/', flags=re.S).sub('', proto) 1108d966dc65SMauro Carvalho Chehab 1109d966dc65SMauro Carvalho Chehab # Parse function typedef prototypes 1110d966dc65SMauro Carvalho Chehab for r in [typedef1, typedef2]: 1111d966dc65SMauro Carvalho Chehab if not r.match(proto): 1112d966dc65SMauro Carvalho Chehab continue 1113d966dc65SMauro Carvalho Chehab 1114d966dc65SMauro Carvalho Chehab return_type = r.group(1).strip() 1115d966dc65SMauro Carvalho Chehab declaration_name = r.group(2) 1116d966dc65SMauro Carvalho Chehab args = r.group(3) 1117d966dc65SMauro Carvalho Chehab 1118d966dc65SMauro Carvalho Chehab if self.entry.identifier != declaration_name: 1119*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1120d966dc65SMauro Carvalho Chehab f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") 1121d966dc65SMauro Carvalho Chehab return 1122d966dc65SMauro Carvalho Chehab 1123d966dc65SMauro Carvalho Chehab decl_type = 'function' 1124d966dc65SMauro Carvalho Chehab self.create_parameter_list(ln, decl_type, args, ',', declaration_name) 1125d966dc65SMauro Carvalho Chehab 1126d966dc65SMauro Carvalho Chehab self.output_declaration(decl_type, declaration_name, 1127d966dc65SMauro Carvalho Chehab function=declaration_name, 1128d966dc65SMauro Carvalho Chehab typedef=True, 1129d966dc65SMauro Carvalho Chehab functiontype=return_type, 1130d966dc65SMauro Carvalho Chehab parameterlist=self.entry.parameterlist, 1131d966dc65SMauro Carvalho Chehab parameterdescs=self.entry.parameterdescs, 1132d966dc65SMauro Carvalho Chehab parametertypes=self.entry.parametertypes, 1133c3597ab2SMauro Carvalho Chehab parameterdesc_start_lines=self.entry.parameterdesc_start_lines, 1134d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 1135d966dc65SMauro Carvalho Chehab sections=self.entry.sections, 1136c3597ab2SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines, 1137d966dc65SMauro Carvalho Chehab purpose=self.entry.declaration_purpose) 1138d966dc65SMauro Carvalho Chehab return 1139d966dc65SMauro Carvalho Chehab 1140d966dc65SMauro Carvalho Chehab # Handle nested parentheses or brackets 114104a383ceSMauro Carvalho Chehab r = KernRe(r'(\(*.\)\s*|\[*.\]\s*);$') 1142d966dc65SMauro Carvalho Chehab while r.search(proto): 1143d966dc65SMauro Carvalho Chehab proto = r.sub('', proto) 1144d966dc65SMauro Carvalho Chehab 1145d966dc65SMauro Carvalho Chehab # Parse simple typedefs 114604a383ceSMauro Carvalho Chehab r = KernRe(r'typedef.*\s+(\w+)\s*;') 1147d966dc65SMauro Carvalho Chehab if r.match(proto): 1148d966dc65SMauro Carvalho Chehab declaration_name = r.group(1) 1149d966dc65SMauro Carvalho Chehab 1150d966dc65SMauro Carvalho Chehab if self.entry.identifier != declaration_name: 1151*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1152*e3b42e94SMauro Carvalho Chehab f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") 1153d966dc65SMauro Carvalho Chehab return 1154d966dc65SMauro Carvalho Chehab 1155d966dc65SMauro Carvalho Chehab self.output_declaration('typedef', declaration_name, 1156d966dc65SMauro Carvalho Chehab typedef=declaration_name, 1157d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 1158d966dc65SMauro Carvalho Chehab sections=self.entry.sections, 1159c3597ab2SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines, 1160d966dc65SMauro Carvalho Chehab purpose=self.entry.declaration_purpose) 1161d966dc65SMauro Carvalho Chehab return 1162d966dc65SMauro Carvalho Chehab 1163*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, "error: Cannot parse typedef!") 1164d966dc65SMauro Carvalho Chehab 1165d966dc65SMauro Carvalho Chehab @staticmethod 116616740c29SMauro Carvalho Chehab def process_export(function_set, line): 1167d966dc65SMauro Carvalho Chehab """ 1168d966dc65SMauro Carvalho Chehab process EXPORT_SYMBOL* tags 1169d966dc65SMauro Carvalho Chehab 117016740c29SMauro Carvalho Chehab This method doesn't use any variable from the class, so declare it 117116740c29SMauro Carvalho Chehab with a staticmethod decorator. 1172d966dc65SMauro Carvalho Chehab """ 1173d966dc65SMauro Carvalho Chehab 117416740c29SMauro Carvalho Chehab # Note: it accepts only one EXPORT_SYMBOL* per line, as having 117516740c29SMauro Carvalho Chehab # multiple export lines would violate Kernel coding style. 117616740c29SMauro Carvalho Chehab 1177d966dc65SMauro Carvalho Chehab if export_symbol.search(line): 1178d966dc65SMauro Carvalho Chehab symbol = export_symbol.group(2) 117916740c29SMauro Carvalho Chehab function_set.add(symbol) 118016740c29SMauro Carvalho Chehab return 1181d966dc65SMauro Carvalho Chehab 1182d966dc65SMauro Carvalho Chehab if export_symbol_ns.search(line): 1183d966dc65SMauro Carvalho Chehab symbol = export_symbol_ns.group(2) 118416740c29SMauro Carvalho Chehab function_set.add(symbol) 1185d966dc65SMauro Carvalho Chehab 1186d966dc65SMauro Carvalho Chehab def process_normal(self, ln, line): 1187d966dc65SMauro Carvalho Chehab """ 1188d966dc65SMauro Carvalho Chehab STATE_NORMAL: looking for the /** to begin everything. 1189d966dc65SMauro Carvalho Chehab """ 1190d966dc65SMauro Carvalho Chehab 1191d966dc65SMauro Carvalho Chehab if not doc_start.match(line): 1192d966dc65SMauro Carvalho Chehab return 1193d966dc65SMauro Carvalho Chehab 1194d966dc65SMauro Carvalho Chehab # start a new entry 1195c3597ab2SMauro Carvalho Chehab self.reset_state(ln) 1196d966dc65SMauro Carvalho Chehab self.entry.in_doc_sect = False 1197d966dc65SMauro Carvalho Chehab 1198d966dc65SMauro Carvalho Chehab # next line is always the function name 1199f9cdbc57SMauro Carvalho Chehab self.state = state.NAME 1200d966dc65SMauro Carvalho Chehab 1201d966dc65SMauro Carvalho Chehab def process_name(self, ln, line): 1202d966dc65SMauro Carvalho Chehab """ 1203d966dc65SMauro Carvalho Chehab STATE_NAME: Looking for the "name - description" line 1204d966dc65SMauro Carvalho Chehab """ 1205d966dc65SMauro Carvalho Chehab 1206d966dc65SMauro Carvalho Chehab if doc_block.search(line): 1207d966dc65SMauro Carvalho Chehab self.entry.new_start_line = ln 1208d966dc65SMauro Carvalho Chehab 1209d966dc65SMauro Carvalho Chehab if not doc_block.group(1): 1210d966dc65SMauro Carvalho Chehab self.entry.section = self.section_intro 1211d966dc65SMauro Carvalho Chehab else: 1212d966dc65SMauro Carvalho Chehab self.entry.section = doc_block.group(1) 1213d966dc65SMauro Carvalho Chehab 1214408269aeSMauro Carvalho Chehab self.entry.identifier = self.entry.section 1215f9cdbc57SMauro Carvalho Chehab self.state = state.DOCBLOCK 1216d966dc65SMauro Carvalho Chehab return 1217d966dc65SMauro Carvalho Chehab 1218d966dc65SMauro Carvalho Chehab if doc_decl.search(line): 1219d966dc65SMauro Carvalho Chehab self.entry.identifier = doc_decl.group(1) 1220d966dc65SMauro Carvalho Chehab self.entry.is_kernel_comment = False 1221d966dc65SMauro Carvalho Chehab 1222d966dc65SMauro Carvalho Chehab decl_start = str(doc_com) # comment block asterisk 1223d966dc65SMauro Carvalho Chehab fn_type = r"(?:\w+\s*\*\s*)?" # type (for non-functions) 1224d966dc65SMauro Carvalho Chehab parenthesis = r"(?:\(\w*\))?" # optional parenthesis on function 1225d966dc65SMauro Carvalho Chehab decl_end = r"(?:[-:].*)" # end of the name part 1226d966dc65SMauro Carvalho Chehab 1227d966dc65SMauro Carvalho Chehab # test for pointer declaration type, foo * bar() - desc 122804a383ceSMauro Carvalho Chehab r = KernRe(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$") 1229d966dc65SMauro Carvalho Chehab if r.search(line): 1230d966dc65SMauro Carvalho Chehab self.entry.identifier = r.group(1) 1231d966dc65SMauro Carvalho Chehab 1232d966dc65SMauro Carvalho Chehab # Test for data declaration 123304a383ceSMauro Carvalho Chehab r = KernRe(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)") 1234d966dc65SMauro Carvalho Chehab if r.search(line): 1235d966dc65SMauro Carvalho Chehab self.entry.decl_type = r.group(1) 1236d966dc65SMauro Carvalho Chehab self.entry.identifier = r.group(2) 1237d966dc65SMauro Carvalho Chehab self.entry.is_kernel_comment = True 1238d966dc65SMauro Carvalho Chehab else: 1239d966dc65SMauro Carvalho Chehab # Look for foo() or static void foo() - description; 1240d966dc65SMauro Carvalho Chehab # or misspelt identifier 1241d966dc65SMauro Carvalho Chehab 124204a383ceSMauro Carvalho Chehab r1 = KernRe(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$") 124304a383ceSMauro Carvalho Chehab r2 = KernRe(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$") 1244d966dc65SMauro Carvalho Chehab 1245d966dc65SMauro Carvalho Chehab for r in [r1, r2]: 1246d966dc65SMauro Carvalho Chehab if r.search(line): 1247d966dc65SMauro Carvalho Chehab self.entry.identifier = r.group(1) 1248d966dc65SMauro Carvalho Chehab self.entry.decl_type = "function" 1249d966dc65SMauro Carvalho Chehab 125004a383ceSMauro Carvalho Chehab r = KernRe(r"define\s+") 1251d966dc65SMauro Carvalho Chehab self.entry.identifier = r.sub("", self.entry.identifier) 1252d966dc65SMauro Carvalho Chehab self.entry.is_kernel_comment = True 1253d966dc65SMauro Carvalho Chehab break 1254d966dc65SMauro Carvalho Chehab 1255d966dc65SMauro Carvalho Chehab self.entry.identifier = self.entry.identifier.strip(" ") 1256d966dc65SMauro Carvalho Chehab 1257f9cdbc57SMauro Carvalho Chehab self.state = state.BODY 1258d966dc65SMauro Carvalho Chehab 1259d966dc65SMauro Carvalho Chehab # if there's no @param blocks need to set up default section here 1260*e3b42e94SMauro Carvalho Chehab self.entry.section = SECTION_DEFAULT 1261d966dc65SMauro Carvalho Chehab self.entry.new_start_line = ln + 1 1262d966dc65SMauro Carvalho Chehab 126304a383ceSMauro Carvalho Chehab r = KernRe("[-:](.*)") 1264d966dc65SMauro Carvalho Chehab if r.search(line): 1265d966dc65SMauro Carvalho Chehab # strip leading/trailing/multiple spaces 1266d966dc65SMauro Carvalho Chehab self.entry.descr = r.group(1).strip(" ") 1267d966dc65SMauro Carvalho Chehab 126804a383ceSMauro Carvalho Chehab r = KernRe(r"\s+") 1269d966dc65SMauro Carvalho Chehab self.entry.descr = r.sub(" ", self.entry.descr) 1270d966dc65SMauro Carvalho Chehab self.entry.declaration_purpose = self.entry.descr 1271f9cdbc57SMauro Carvalho Chehab self.state = state.BODY_MAYBE 1272d966dc65SMauro Carvalho Chehab else: 1273d966dc65SMauro Carvalho Chehab self.entry.declaration_purpose = "" 1274d966dc65SMauro Carvalho Chehab 1275d966dc65SMauro Carvalho Chehab if not self.entry.is_kernel_comment: 1276*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1277d966dc65SMauro Carvalho Chehab f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}") 1278f9cdbc57SMauro Carvalho Chehab self.state = state.NORMAL 1279d966dc65SMauro Carvalho Chehab 1280d966dc65SMauro Carvalho Chehab if not self.entry.declaration_purpose and self.config.wshort_desc: 1281*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1282d966dc65SMauro Carvalho Chehab f"missing initial short description on line:\n{line}") 1283d966dc65SMauro Carvalho Chehab 1284d966dc65SMauro Carvalho Chehab if not self.entry.identifier and self.entry.decl_type != "enum": 1285*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1286d966dc65SMauro Carvalho Chehab f"wrong kernel-doc identifier on line:\n{line}") 1287f9cdbc57SMauro Carvalho Chehab self.state = state.NORMAL 1288d966dc65SMauro Carvalho Chehab 1289d966dc65SMauro Carvalho Chehab if self.config.verbose: 1290*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1291d966dc65SMauro Carvalho Chehab f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}", 1292d966dc65SMauro Carvalho Chehab warning=False) 1293d966dc65SMauro Carvalho Chehab 1294d966dc65SMauro Carvalho Chehab return 1295d966dc65SMauro Carvalho Chehab 1296d966dc65SMauro Carvalho Chehab # Failed to find an identifier. Emit a warning 1297*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"Cannot find identifier on line:\n{line}") 1298d966dc65SMauro Carvalho Chehab 1299d966dc65SMauro Carvalho Chehab def process_body(self, ln, line): 1300d966dc65SMauro Carvalho Chehab """ 1301d966dc65SMauro Carvalho Chehab STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment. 1302d966dc65SMauro Carvalho Chehab """ 1303d966dc65SMauro Carvalho Chehab 1304f9cdbc57SMauro Carvalho Chehab if self.state == state.BODY_WITH_BLANK_LINE: 130504a383ceSMauro Carvalho Chehab r = KernRe(r"\s*\*\s?\S") 1306d966dc65SMauro Carvalho Chehab if r.match(line): 1307d966dc65SMauro Carvalho Chehab self.dump_section() 1308*e3b42e94SMauro Carvalho Chehab self.entry.section = SECTION_DEFAULT 1309c3597ab2SMauro Carvalho Chehab self.entry.new_start_line = ln 1310d966dc65SMauro Carvalho Chehab self.entry.contents = "" 1311d966dc65SMauro Carvalho Chehab 1312d966dc65SMauro Carvalho Chehab if doc_sect.search(line): 1313d966dc65SMauro Carvalho Chehab self.entry.in_doc_sect = True 1314d966dc65SMauro Carvalho Chehab newsection = doc_sect.group(1) 1315d966dc65SMauro Carvalho Chehab 1316d966dc65SMauro Carvalho Chehab if newsection.lower() in ["description", "context"]: 1317d966dc65SMauro Carvalho Chehab newsection = newsection.title() 1318d966dc65SMauro Carvalho Chehab 1319d966dc65SMauro Carvalho Chehab # Special case: @return is a section, not a param description 1320d966dc65SMauro Carvalho Chehab if newsection.lower() in ["@return", "@returns", 1321d966dc65SMauro Carvalho Chehab "return", "returns"]: 1322d966dc65SMauro Carvalho Chehab newsection = "Return" 1323d966dc65SMauro Carvalho Chehab 1324d966dc65SMauro Carvalho Chehab # Perl kernel-doc has a check here for contents before sections. 1325d966dc65SMauro Carvalho Chehab # the logic there is always false, as in_doc_sect variable is 1326d966dc65SMauro Carvalho Chehab # always true. So, just don't implement Wcontents_before_sections 1327d966dc65SMauro Carvalho Chehab 1328d966dc65SMauro Carvalho Chehab # .title() 1329d966dc65SMauro Carvalho Chehab newcontents = doc_sect.group(2) 1330d966dc65SMauro Carvalho Chehab if not newcontents: 1331d966dc65SMauro Carvalho Chehab newcontents = "" 1332d966dc65SMauro Carvalho Chehab 1333d966dc65SMauro Carvalho Chehab if self.entry.contents.strip("\n"): 1334d966dc65SMauro Carvalho Chehab self.dump_section() 1335d966dc65SMauro Carvalho Chehab 1336d966dc65SMauro Carvalho Chehab self.entry.new_start_line = ln 1337d966dc65SMauro Carvalho Chehab self.entry.section = newsection 1338d966dc65SMauro Carvalho Chehab self.entry.leading_space = None 1339d966dc65SMauro Carvalho Chehab 1340d966dc65SMauro Carvalho Chehab self.entry.contents = newcontents.lstrip() 1341d966dc65SMauro Carvalho Chehab if self.entry.contents: 1342d966dc65SMauro Carvalho Chehab self.entry.contents += "\n" 1343d966dc65SMauro Carvalho Chehab 1344f9cdbc57SMauro Carvalho Chehab self.state = state.BODY 1345d966dc65SMauro Carvalho Chehab return 1346d966dc65SMauro Carvalho Chehab 1347d966dc65SMauro Carvalho Chehab if doc_end.search(line): 1348d966dc65SMauro Carvalho Chehab self.dump_section() 1349d966dc65SMauro Carvalho Chehab 1350d966dc65SMauro Carvalho Chehab # Look for doc_com + <text> + doc_end: 135104a383ceSMauro Carvalho Chehab r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') 1352d966dc65SMauro Carvalho Chehab if r.match(line): 1353*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"suspicious ending line: {line}") 1354d966dc65SMauro Carvalho Chehab 1355d966dc65SMauro Carvalho Chehab self.entry.prototype = "" 1356d966dc65SMauro Carvalho Chehab self.entry.new_start_line = ln + 1 1357d966dc65SMauro Carvalho Chehab 1358f9cdbc57SMauro Carvalho Chehab self.state = state.PROTO 1359d966dc65SMauro Carvalho Chehab return 1360d966dc65SMauro Carvalho Chehab 1361d966dc65SMauro Carvalho Chehab if doc_content.search(line): 1362d966dc65SMauro Carvalho Chehab cont = doc_content.group(1) 1363d966dc65SMauro Carvalho Chehab 1364d966dc65SMauro Carvalho Chehab if cont == "": 1365d966dc65SMauro Carvalho Chehab if self.entry.section == self.section_context: 1366d966dc65SMauro Carvalho Chehab self.dump_section() 1367d966dc65SMauro Carvalho Chehab 1368d966dc65SMauro Carvalho Chehab self.entry.new_start_line = ln 1369f9cdbc57SMauro Carvalho Chehab self.state = state.BODY 1370d966dc65SMauro Carvalho Chehab else: 1371*e3b42e94SMauro Carvalho Chehab if self.entry.section != SECTION_DEFAULT: 1372f9cdbc57SMauro Carvalho Chehab self.state = state.BODY_WITH_BLANK_LINE 1373d966dc65SMauro Carvalho Chehab else: 1374f9cdbc57SMauro Carvalho Chehab self.state = state.BODY 1375d966dc65SMauro Carvalho Chehab 1376d966dc65SMauro Carvalho Chehab self.entry.contents += "\n" 1377d966dc65SMauro Carvalho Chehab 1378f9cdbc57SMauro Carvalho Chehab elif self.state == state.BODY_MAYBE: 1379d966dc65SMauro Carvalho Chehab 1380d966dc65SMauro Carvalho Chehab # Continued declaration purpose 1381d966dc65SMauro Carvalho Chehab self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip() 1382d966dc65SMauro Carvalho Chehab self.entry.declaration_purpose += " " + cont 1383d966dc65SMauro Carvalho Chehab 138404a383ceSMauro Carvalho Chehab r = KernRe(r"\s+") 1385d966dc65SMauro Carvalho Chehab self.entry.declaration_purpose = r.sub(' ', 1386d966dc65SMauro Carvalho Chehab self.entry.declaration_purpose) 1387d966dc65SMauro Carvalho Chehab 1388d966dc65SMauro Carvalho Chehab else: 1389d966dc65SMauro Carvalho Chehab if self.entry.section.startswith('@') or \ 1390d966dc65SMauro Carvalho Chehab self.entry.section == self.section_context: 1391d966dc65SMauro Carvalho Chehab if self.entry.leading_space is None: 139204a383ceSMauro Carvalho Chehab r = KernRe(r'^(\s+)') 1393d966dc65SMauro Carvalho Chehab if r.match(cont): 1394d966dc65SMauro Carvalho Chehab self.entry.leading_space = len(r.group(1)) 1395d966dc65SMauro Carvalho Chehab else: 1396d966dc65SMauro Carvalho Chehab self.entry.leading_space = 0 1397d966dc65SMauro Carvalho Chehab 1398d966dc65SMauro Carvalho Chehab # Double-check if leading space are realy spaces 1399d966dc65SMauro Carvalho Chehab pos = 0 1400d966dc65SMauro Carvalho Chehab for i in range(0, self.entry.leading_space): 1401d966dc65SMauro Carvalho Chehab if cont[i] != " ": 1402d966dc65SMauro Carvalho Chehab break 1403d966dc65SMauro Carvalho Chehab pos += 1 1404d966dc65SMauro Carvalho Chehab 1405d966dc65SMauro Carvalho Chehab cont = cont[pos:] 1406d966dc65SMauro Carvalho Chehab 1407d966dc65SMauro Carvalho Chehab # NEW LOGIC: 1408d966dc65SMauro Carvalho Chehab # In case it is different, update it 1409d966dc65SMauro Carvalho Chehab if self.entry.leading_space != pos: 1410d966dc65SMauro Carvalho Chehab self.entry.leading_space = pos 1411d966dc65SMauro Carvalho Chehab 1412d966dc65SMauro Carvalho Chehab self.entry.contents += cont + "\n" 1413d966dc65SMauro Carvalho Chehab return 1414d966dc65SMauro Carvalho Chehab 1415d966dc65SMauro Carvalho Chehab # Unknown line, ignore 1416*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, f"bad line: {line}") 1417d966dc65SMauro Carvalho Chehab 1418d966dc65SMauro Carvalho Chehab def process_inline(self, ln, line): 1419d966dc65SMauro Carvalho Chehab """STATE_INLINE: docbook comments within a prototype.""" 1420d966dc65SMauro Carvalho Chehab 1421f9cdbc57SMauro Carvalho Chehab if self.inline_doc_state == state.INLINE_NAME and \ 1422d966dc65SMauro Carvalho Chehab doc_inline_sect.search(line): 1423d966dc65SMauro Carvalho Chehab self.entry.section = doc_inline_sect.group(1) 1424d966dc65SMauro Carvalho Chehab self.entry.new_start_line = ln 1425d966dc65SMauro Carvalho Chehab 1426d966dc65SMauro Carvalho Chehab self.entry.contents = doc_inline_sect.group(2).lstrip() 1427d966dc65SMauro Carvalho Chehab if self.entry.contents != "": 1428d966dc65SMauro Carvalho Chehab self.entry.contents += "\n" 1429d966dc65SMauro Carvalho Chehab 1430f9cdbc57SMauro Carvalho Chehab self.inline_doc_state = state.INLINE_TEXT 1431d966dc65SMauro Carvalho Chehab # Documentation block end */ 1432d966dc65SMauro Carvalho Chehab return 1433d966dc65SMauro Carvalho Chehab 1434d966dc65SMauro Carvalho Chehab if doc_inline_end.search(line): 1435d966dc65SMauro Carvalho Chehab if self.entry.contents not in ["", "\n"]: 1436d966dc65SMauro Carvalho Chehab self.dump_section() 1437d966dc65SMauro Carvalho Chehab 1438f9cdbc57SMauro Carvalho Chehab self.state = state.PROTO 1439f9cdbc57SMauro Carvalho Chehab self.inline_doc_state = state.INLINE_NA 1440d966dc65SMauro Carvalho Chehab return 1441d966dc65SMauro Carvalho Chehab 1442d966dc65SMauro Carvalho Chehab if doc_content.search(line): 1443f9cdbc57SMauro Carvalho Chehab if self.inline_doc_state == state.INLINE_TEXT: 1444d966dc65SMauro Carvalho Chehab self.entry.contents += doc_content.group(1) + "\n" 1445d966dc65SMauro Carvalho Chehab if not self.entry.contents.strip(" ").rstrip("\n"): 1446d966dc65SMauro Carvalho Chehab self.entry.contents = "" 1447d966dc65SMauro Carvalho Chehab 1448f9cdbc57SMauro Carvalho Chehab elif self.inline_doc_state == state.INLINE_NAME: 1449*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1450d966dc65SMauro Carvalho Chehab f"Incorrect use of kernel-doc format: {line}") 1451d966dc65SMauro Carvalho Chehab 1452f9cdbc57SMauro Carvalho Chehab self.inline_doc_state = state.INLINE_ERROR 1453d966dc65SMauro Carvalho Chehab 1454d966dc65SMauro Carvalho Chehab def syscall_munge(self, ln, proto): # pylint: disable=W0613 1455d966dc65SMauro Carvalho Chehab """ 1456d966dc65SMauro Carvalho Chehab Handle syscall definitions 1457d966dc65SMauro Carvalho Chehab """ 1458d966dc65SMauro Carvalho Chehab 1459d966dc65SMauro Carvalho Chehab is_void = False 1460d966dc65SMauro Carvalho Chehab 1461d966dc65SMauro Carvalho Chehab # Strip newlines/CR's 1462d966dc65SMauro Carvalho Chehab proto = re.sub(r'[\r\n]+', ' ', proto) 1463d966dc65SMauro Carvalho Chehab 1464d966dc65SMauro Carvalho Chehab # Check if it's a SYSCALL_DEFINE0 1465d966dc65SMauro Carvalho Chehab if 'SYSCALL_DEFINE0' in proto: 1466d966dc65SMauro Carvalho Chehab is_void = True 1467d966dc65SMauro Carvalho Chehab 1468d966dc65SMauro Carvalho Chehab # Replace SYSCALL_DEFINE with correct return type & function name 146904a383ceSMauro Carvalho Chehab proto = KernRe(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto) 1470d966dc65SMauro Carvalho Chehab 147104a383ceSMauro Carvalho Chehab r = KernRe(r'long\s+(sys_.*?),') 1472d966dc65SMauro Carvalho Chehab if r.search(proto): 147304a383ceSMauro Carvalho Chehab proto = KernRe(',').sub('(', proto, count=1) 1474d966dc65SMauro Carvalho Chehab elif is_void: 147504a383ceSMauro Carvalho Chehab proto = KernRe(r'\)').sub('(void)', proto, count=1) 1476d966dc65SMauro Carvalho Chehab 1477d966dc65SMauro Carvalho Chehab # Now delete all of the odd-numbered commas in the proto 1478d966dc65SMauro Carvalho Chehab # so that argument types & names don't have a comma between them 1479d966dc65SMauro Carvalho Chehab count = 0 1480d966dc65SMauro Carvalho Chehab length = len(proto) 1481d966dc65SMauro Carvalho Chehab 1482d966dc65SMauro Carvalho Chehab if is_void: 1483d966dc65SMauro Carvalho Chehab length = 0 # skip the loop if is_void 1484d966dc65SMauro Carvalho Chehab 1485d966dc65SMauro Carvalho Chehab for ix in range(length): 1486d966dc65SMauro Carvalho Chehab if proto[ix] == ',': 1487d966dc65SMauro Carvalho Chehab count += 1 1488d966dc65SMauro Carvalho Chehab if count % 2 == 1: 1489d966dc65SMauro Carvalho Chehab proto = proto[:ix] + ' ' + proto[ix + 1:] 1490d966dc65SMauro Carvalho Chehab 1491d966dc65SMauro Carvalho Chehab return proto 1492d966dc65SMauro Carvalho Chehab 1493d966dc65SMauro Carvalho Chehab def tracepoint_munge(self, ln, proto): 1494d966dc65SMauro Carvalho Chehab """ 1495d966dc65SMauro Carvalho Chehab Handle tracepoint definitions 1496d966dc65SMauro Carvalho Chehab """ 1497d966dc65SMauro Carvalho Chehab 1498d966dc65SMauro Carvalho Chehab tracepointname = None 1499d966dc65SMauro Carvalho Chehab tracepointargs = None 1500d966dc65SMauro Carvalho Chehab 1501d966dc65SMauro Carvalho Chehab # Match tracepoint name based on different patterns 150204a383ceSMauro Carvalho Chehab r = KernRe(r'TRACE_EVENT\((.*?),') 1503d966dc65SMauro Carvalho Chehab if r.search(proto): 1504d966dc65SMauro Carvalho Chehab tracepointname = r.group(1) 1505d966dc65SMauro Carvalho Chehab 150604a383ceSMauro Carvalho Chehab r = KernRe(r'DEFINE_SINGLE_EVENT\((.*?),') 1507d966dc65SMauro Carvalho Chehab if r.search(proto): 1508d966dc65SMauro Carvalho Chehab tracepointname = r.group(1) 1509d966dc65SMauro Carvalho Chehab 151004a383ceSMauro Carvalho Chehab r = KernRe(r'DEFINE_EVENT\((.*?),(.*?),') 1511d966dc65SMauro Carvalho Chehab if r.search(proto): 1512d966dc65SMauro Carvalho Chehab tracepointname = r.group(2) 1513d966dc65SMauro Carvalho Chehab 1514d966dc65SMauro Carvalho Chehab if tracepointname: 1515d966dc65SMauro Carvalho Chehab tracepointname = tracepointname.lstrip() 1516d966dc65SMauro Carvalho Chehab 151704a383ceSMauro Carvalho Chehab r = KernRe(r'TP_PROTO\((.*?)\)') 1518d966dc65SMauro Carvalho Chehab if r.search(proto): 1519d966dc65SMauro Carvalho Chehab tracepointargs = r.group(1) 1520d966dc65SMauro Carvalho Chehab 1521d966dc65SMauro Carvalho Chehab if not tracepointname or not tracepointargs: 1522*e3b42e94SMauro Carvalho Chehab self.emit_msg(ln, 1523d966dc65SMauro Carvalho Chehab f"Unrecognized tracepoint format:\n{proto}\n") 1524d966dc65SMauro Carvalho Chehab else: 1525d966dc65SMauro Carvalho Chehab proto = f"static inline void trace_{tracepointname}({tracepointargs})" 1526d966dc65SMauro Carvalho Chehab self.entry.identifier = f"trace_{self.entry.identifier}" 1527d966dc65SMauro Carvalho Chehab 1528d966dc65SMauro Carvalho Chehab return proto 1529d966dc65SMauro Carvalho Chehab 1530d966dc65SMauro Carvalho Chehab def process_proto_function(self, ln, line): 1531d966dc65SMauro Carvalho Chehab """Ancillary routine to process a function prototype""" 1532d966dc65SMauro Carvalho Chehab 1533d966dc65SMauro Carvalho Chehab # strip C99-style comments to end of line 153404a383ceSMauro Carvalho Chehab r = KernRe(r"\/\/.*$", re.S) 1535d966dc65SMauro Carvalho Chehab line = r.sub('', line) 1536d966dc65SMauro Carvalho Chehab 153704a383ceSMauro Carvalho Chehab if KernRe(r'\s*#\s*define').match(line): 1538d966dc65SMauro Carvalho Chehab self.entry.prototype = line 1539d966dc65SMauro Carvalho Chehab elif line.startswith('#'): 1540d966dc65SMauro Carvalho Chehab # Strip other macros like #ifdef/#ifndef/#endif/... 1541d966dc65SMauro Carvalho Chehab pass 1542d966dc65SMauro Carvalho Chehab else: 154304a383ceSMauro Carvalho Chehab r = KernRe(r'([^\{]*)') 1544d966dc65SMauro Carvalho Chehab if r.match(line): 1545d966dc65SMauro Carvalho Chehab self.entry.prototype += r.group(1) + " " 1546d966dc65SMauro Carvalho Chehab 154704a383ceSMauro Carvalho Chehab if '{' in line or ';' in line or KernRe(r'\s*#\s*define').match(line): 1548d966dc65SMauro Carvalho Chehab # strip comments 154904a383ceSMauro Carvalho Chehab r = KernRe(r'/\*.*?\*/') 1550d966dc65SMauro Carvalho Chehab self.entry.prototype = r.sub('', self.entry.prototype) 1551d966dc65SMauro Carvalho Chehab 1552d966dc65SMauro Carvalho Chehab # strip newlines/cr's 155304a383ceSMauro Carvalho Chehab r = KernRe(r'[\r\n]+') 1554d966dc65SMauro Carvalho Chehab self.entry.prototype = r.sub(' ', self.entry.prototype) 1555d966dc65SMauro Carvalho Chehab 1556d966dc65SMauro Carvalho Chehab # strip leading spaces 155704a383ceSMauro Carvalho Chehab r = KernRe(r'^\s+') 1558d966dc65SMauro Carvalho Chehab self.entry.prototype = r.sub('', self.entry.prototype) 1559d966dc65SMauro Carvalho Chehab 1560d966dc65SMauro Carvalho Chehab # Handle self.entry.prototypes for function pointers like: 1561d966dc65SMauro Carvalho Chehab # int (*pcs_config)(struct foo) 1562d966dc65SMauro Carvalho Chehab 156304a383ceSMauro Carvalho Chehab r = KernRe(r'^(\S+\s+)\(\s*\*(\S+)\)') 1564d966dc65SMauro Carvalho Chehab self.entry.prototype = r.sub(r'\1\2', self.entry.prototype) 1565d966dc65SMauro Carvalho Chehab 1566d966dc65SMauro Carvalho Chehab if 'SYSCALL_DEFINE' in self.entry.prototype: 1567d966dc65SMauro Carvalho Chehab self.entry.prototype = self.syscall_munge(ln, 1568d966dc65SMauro Carvalho Chehab self.entry.prototype) 1569d966dc65SMauro Carvalho Chehab 157004a383ceSMauro Carvalho Chehab r = KernRe(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT') 1571d966dc65SMauro Carvalho Chehab if r.search(self.entry.prototype): 1572d966dc65SMauro Carvalho Chehab self.entry.prototype = self.tracepoint_munge(ln, 1573d966dc65SMauro Carvalho Chehab self.entry.prototype) 1574d966dc65SMauro Carvalho Chehab 1575d966dc65SMauro Carvalho Chehab self.dump_function(ln, self.entry.prototype) 1576d966dc65SMauro Carvalho Chehab self.reset_state(ln) 1577d966dc65SMauro Carvalho Chehab 1578d966dc65SMauro Carvalho Chehab def process_proto_type(self, ln, line): 1579d966dc65SMauro Carvalho Chehab """Ancillary routine to process a type""" 1580d966dc65SMauro Carvalho Chehab 1581d966dc65SMauro Carvalho Chehab # Strip newlines/cr's. 158204a383ceSMauro Carvalho Chehab line = KernRe(r'[\r\n]+', re.S).sub(' ', line) 1583d966dc65SMauro Carvalho Chehab 1584d966dc65SMauro Carvalho Chehab # Strip leading spaces 158504a383ceSMauro Carvalho Chehab line = KernRe(r'^\s+', re.S).sub('', line) 1586d966dc65SMauro Carvalho Chehab 1587d966dc65SMauro Carvalho Chehab # Strip trailing spaces 158804a383ceSMauro Carvalho Chehab line = KernRe(r'\s+$', re.S).sub('', line) 1589d966dc65SMauro Carvalho Chehab 1590d966dc65SMauro Carvalho Chehab # Strip C99-style comments to the end of the line 159104a383ceSMauro Carvalho Chehab line = KernRe(r"\/\/.*$", re.S).sub('', line) 1592d966dc65SMauro Carvalho Chehab 1593d966dc65SMauro Carvalho Chehab # To distinguish preprocessor directive from regular declaration later. 1594d966dc65SMauro Carvalho Chehab if line.startswith('#'): 1595d966dc65SMauro Carvalho Chehab line += ";" 1596d966dc65SMauro Carvalho Chehab 159704a383ceSMauro Carvalho Chehab r = KernRe(r'([^\{\};]*)([\{\};])(.*)') 1598d966dc65SMauro Carvalho Chehab while True: 1599d966dc65SMauro Carvalho Chehab if r.search(line): 1600d966dc65SMauro Carvalho Chehab if self.entry.prototype: 1601d966dc65SMauro Carvalho Chehab self.entry.prototype += " " 1602d966dc65SMauro Carvalho Chehab self.entry.prototype += r.group(1) + r.group(2) 1603d966dc65SMauro Carvalho Chehab 1604d966dc65SMauro Carvalho Chehab self.entry.brcount += r.group(2).count('{') 1605d966dc65SMauro Carvalho Chehab self.entry.brcount -= r.group(2).count('}') 1606d966dc65SMauro Carvalho Chehab 1607d966dc65SMauro Carvalho Chehab self.entry.brcount = max(self.entry.brcount, 0) 1608d966dc65SMauro Carvalho Chehab 1609d966dc65SMauro Carvalho Chehab if r.group(2) == ';' and self.entry.brcount == 0: 1610d966dc65SMauro Carvalho Chehab self.dump_declaration(ln, self.entry.prototype) 1611d966dc65SMauro Carvalho Chehab self.reset_state(ln) 1612d966dc65SMauro Carvalho Chehab break 1613d966dc65SMauro Carvalho Chehab 1614d966dc65SMauro Carvalho Chehab line = r.group(3) 1615d966dc65SMauro Carvalho Chehab else: 1616d966dc65SMauro Carvalho Chehab self.entry.prototype += line 1617d966dc65SMauro Carvalho Chehab break 1618d966dc65SMauro Carvalho Chehab 1619d966dc65SMauro Carvalho Chehab def process_proto(self, ln, line): 1620d966dc65SMauro Carvalho Chehab """STATE_PROTO: reading a function/whatever prototype.""" 1621d966dc65SMauro Carvalho Chehab 1622d966dc65SMauro Carvalho Chehab if doc_inline_oneline.search(line): 1623d966dc65SMauro Carvalho Chehab self.entry.section = doc_inline_oneline.group(1) 1624d966dc65SMauro Carvalho Chehab self.entry.contents = doc_inline_oneline.group(2) 1625d966dc65SMauro Carvalho Chehab 1626d966dc65SMauro Carvalho Chehab if self.entry.contents != "": 1627d966dc65SMauro Carvalho Chehab self.entry.contents += "\n" 1628d966dc65SMauro Carvalho Chehab self.dump_section(start_new=False) 1629d966dc65SMauro Carvalho Chehab 1630d966dc65SMauro Carvalho Chehab elif doc_inline_start.search(line): 1631f9cdbc57SMauro Carvalho Chehab self.state = state.INLINE 1632f9cdbc57SMauro Carvalho Chehab self.inline_doc_state = state.INLINE_NAME 1633d966dc65SMauro Carvalho Chehab 1634d966dc65SMauro Carvalho Chehab elif self.entry.decl_type == 'function': 1635d966dc65SMauro Carvalho Chehab self.process_proto_function(ln, line) 1636d966dc65SMauro Carvalho Chehab 1637d966dc65SMauro Carvalho Chehab else: 1638d966dc65SMauro Carvalho Chehab self.process_proto_type(ln, line) 1639d966dc65SMauro Carvalho Chehab 1640d966dc65SMauro Carvalho Chehab def process_docblock(self, ln, line): 1641d966dc65SMauro Carvalho Chehab """STATE_DOCBLOCK: within a DOC: block.""" 1642d966dc65SMauro Carvalho Chehab 1643d966dc65SMauro Carvalho Chehab if doc_end.search(line): 1644d966dc65SMauro Carvalho Chehab self.dump_section() 1645408269aeSMauro Carvalho Chehab self.output_declaration("doc", self.entry.identifier, 1646d966dc65SMauro Carvalho Chehab sectionlist=self.entry.sectionlist, 1647c3597ab2SMauro Carvalho Chehab sections=self.entry.sections, 16482ab867a4SMauro Carvalho Chehab section_start_lines=self.entry.section_start_lines) 1649d966dc65SMauro Carvalho Chehab self.reset_state(ln) 1650d966dc65SMauro Carvalho Chehab 1651d966dc65SMauro Carvalho Chehab elif doc_content.search(line): 1652d966dc65SMauro Carvalho Chehab self.entry.contents += doc_content.group(1) + "\n" 1653d966dc65SMauro Carvalho Chehab 165416740c29SMauro Carvalho Chehab def parse_export(self): 165516740c29SMauro Carvalho Chehab """ 165616740c29SMauro Carvalho Chehab Parses EXPORT_SYMBOL* macros from a single Kernel source file. 165716740c29SMauro Carvalho Chehab """ 165816740c29SMauro Carvalho Chehab 165916740c29SMauro Carvalho Chehab export_table = set() 166016740c29SMauro Carvalho Chehab 166116740c29SMauro Carvalho Chehab try: 166216740c29SMauro Carvalho Chehab with open(self.fname, "r", encoding="utf8", 166316740c29SMauro Carvalho Chehab errors="backslashreplace") as fp: 166416740c29SMauro Carvalho Chehab 166516740c29SMauro Carvalho Chehab for line in fp: 166616740c29SMauro Carvalho Chehab self.process_export(export_table, line) 166716740c29SMauro Carvalho Chehab 166816740c29SMauro Carvalho Chehab except IOError: 166916740c29SMauro Carvalho Chehab return None 167016740c29SMauro Carvalho Chehab 167116740c29SMauro Carvalho Chehab return export_table 167216740c29SMauro Carvalho Chehab 167316740c29SMauro Carvalho Chehab def parse_kdoc(self): 1674d966dc65SMauro Carvalho Chehab """ 1675d966dc65SMauro Carvalho Chehab Open and process each line of a C source file. 167616740c29SMauro Carvalho Chehab The parsing is controlled via a state machine, and the line is passed 1677d966dc65SMauro Carvalho Chehab to a different process function depending on the state. The process 1678d966dc65SMauro Carvalho Chehab function may update the state as needed. 167916740c29SMauro Carvalho Chehab 168016740c29SMauro Carvalho Chehab Besides parsing kernel-doc tags, it also parses export symbols. 1681d966dc65SMauro Carvalho Chehab """ 1682d966dc65SMauro Carvalho Chehab 1683d966dc65SMauro Carvalho Chehab cont = False 1684d966dc65SMauro Carvalho Chehab prev = "" 1685d966dc65SMauro Carvalho Chehab prev_ln = None 168616740c29SMauro Carvalho Chehab export_table = set() 1687d966dc65SMauro Carvalho Chehab 1688d966dc65SMauro Carvalho Chehab try: 1689d966dc65SMauro Carvalho Chehab with open(self.fname, "r", encoding="utf8", 1690d966dc65SMauro Carvalho Chehab errors="backslashreplace") as fp: 1691d966dc65SMauro Carvalho Chehab for ln, line in enumerate(fp): 1692d966dc65SMauro Carvalho Chehab 1693d966dc65SMauro Carvalho Chehab line = line.expandtabs().strip("\n") 1694d966dc65SMauro Carvalho Chehab 1695d966dc65SMauro Carvalho Chehab # Group continuation lines on prototypes 1696f9cdbc57SMauro Carvalho Chehab if self.state == state.PROTO: 1697d966dc65SMauro Carvalho Chehab if line.endswith("\\"): 1698e4b2bd90SMauro Carvalho Chehab prev += line.rstrip("\\") 1699d966dc65SMauro Carvalho Chehab cont = True 1700d966dc65SMauro Carvalho Chehab 1701d966dc65SMauro Carvalho Chehab if not prev_ln: 1702d966dc65SMauro Carvalho Chehab prev_ln = ln 1703d966dc65SMauro Carvalho Chehab 1704d966dc65SMauro Carvalho Chehab continue 1705d966dc65SMauro Carvalho Chehab 1706d966dc65SMauro Carvalho Chehab if cont: 1707d966dc65SMauro Carvalho Chehab ln = prev_ln 1708d966dc65SMauro Carvalho Chehab line = prev + line 1709d966dc65SMauro Carvalho Chehab prev = "" 1710d966dc65SMauro Carvalho Chehab cont = False 1711d966dc65SMauro Carvalho Chehab prev_ln = None 1712d966dc65SMauro Carvalho Chehab 1713d966dc65SMauro Carvalho Chehab self.config.log.debug("%d %s%s: %s", 1714f9cdbc57SMauro Carvalho Chehab ln, state.name[self.state], 1715f9cdbc57SMauro Carvalho Chehab state.inline_name[self.inline_doc_state], 1716d966dc65SMauro Carvalho Chehab line) 1717d966dc65SMauro Carvalho Chehab 171816740c29SMauro Carvalho Chehab # This is an optimization over the original script. 171916740c29SMauro Carvalho Chehab # There, when export_file was used for the same file, 172016740c29SMauro Carvalho Chehab # it was read twice. Here, we use the already-existing 172116740c29SMauro Carvalho Chehab # loop to parse exported symbols as well. 172216740c29SMauro Carvalho Chehab # 172316740c29SMauro Carvalho Chehab # TODO: It should be noticed that not all states are 172416740c29SMauro Carvalho Chehab # needed here. On a future cleanup, process export only 172516740c29SMauro Carvalho Chehab # at the states that aren't handling comment markups. 172616740c29SMauro Carvalho Chehab self.process_export(export_table, line) 172716740c29SMauro Carvalho Chehab 1728d966dc65SMauro Carvalho Chehab # Hand this line to the appropriate state handler 1729f9cdbc57SMauro Carvalho Chehab if self.state == state.NORMAL: 1730d966dc65SMauro Carvalho Chehab self.process_normal(ln, line) 1731f9cdbc57SMauro Carvalho Chehab elif self.state == state.NAME: 1732d966dc65SMauro Carvalho Chehab self.process_name(ln, line) 1733f9cdbc57SMauro Carvalho Chehab elif self.state in [state.BODY, state.BODY_MAYBE, 1734f9cdbc57SMauro Carvalho Chehab state.BODY_WITH_BLANK_LINE]: 1735d966dc65SMauro Carvalho Chehab self.process_body(ln, line) 1736f9cdbc57SMauro Carvalho Chehab elif self.state == state.INLINE: # scanning for inline parameters 1737d966dc65SMauro Carvalho Chehab self.process_inline(ln, line) 1738f9cdbc57SMauro Carvalho Chehab elif self.state == state.PROTO: 1739d966dc65SMauro Carvalho Chehab self.process_proto(ln, line) 1740f9cdbc57SMauro Carvalho Chehab elif self.state == state.DOCBLOCK: 1741d966dc65SMauro Carvalho Chehab self.process_docblock(ln, line) 1742d966dc65SMauro Carvalho Chehab except OSError: 1743d966dc65SMauro Carvalho Chehab self.config.log.error(f"Error: Cannot open file {self.fname}") 174416740c29SMauro Carvalho Chehab 174516740c29SMauro Carvalho Chehab return export_table, self.entries 1746