return_type = r.group(1) declaration_name = r.group(2) args = r.group(3) self.create_parameter_list(ln, decl_type, args, ',', declaration_name) found = True break # # Parsing done; make sure that things are as we expect. # if not found: self.emit_msg(ln, f"cannot understand function prototype: '{prototype}'") return if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for {self.entry.identifier}(). " f"Prototype was for {declaration_name}() instead") return self.check_sections(ln, declaration_name, "function") self.check_return_section(ln, declaration_name, return_type) # # Store the result. # self.output_declaration(decl_type, declaration_name, source=source, typedef=('typedef' in return_type), functiontype=return_type, purpose=self.entry.declaration_purpose, func_macro=func_macro) def dump_typedef(self, ln, proto, source): """ Store a ``typedef`` inside self.entries array. """ # # We start by looking for function typedefs. # typedef_type = r'typedef((?:\s+[\w*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' typedef_ident = r'\*?\s*(\w\S+)\s*' typedef_args = r'\s*\((.*)\);' source = source typedef1 = KernRe(typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args) typedef2 = KernRe(typedef_type + typedef_ident + typedef_args) # Parse function typedef prototypes for r in [typedef1, typedef2]: if not r.match(proto): continue return_type = r.group(1).strip() declaration_name = r.group(2) args = r.group(3) if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") return self.create_parameter_list(ln, 'function', args, ',', declaration_name) self.output_declaration('function', declaration_name, source=source, typedef=True, functiontype=return_type, purpose=self.entry.declaration_purpose) return # # Not a function, try to parse a simple typedef. # r = KernRe(r'typedef.*\s+(\w+)\s*;') if r.match(proto): declaration_name = r.group(1) if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") return self.output_declaration('typedef', declaration_name, source=source, purpose=self.entry.declaration_purpose) return self.emit_msg(ln, "error: Cannot parse typedef!") @staticmethod def process_export(function_set, line): """ process ``EXPORT_SYMBOL*`` tags This method doesn't use any variable from the class, so declare it with a staticmethod decorator. """ # We support documenting some exported symbols with different # names. A horrible hack. suffixes = [ '_noprof' ] # Note: it accepts only one EXPORT_SYMBOL* per line, as having # multiple export lines would violate Kernel coding style. if export_symbol.search(line): symbol = export_symbol.group(2) elif export_symbol_ns.search(line): symbol = export_symbol_ns.group(2) else: return False # # Found an export, trim out any special suffixes # for suffix in suffixes: # Be backward compatible with Python < 3.9 if symbol.endswith(suffix): symbol = symbol[:-len(suffix)] function_set.add(symbol) return True def process_normal(self, ln, line, source): """ STATE_NORMAL: looking for the ``/**`` to begin everything. """ if not doc_start.match(line): return # start a new entry self.reset_state(ln) # next line is always the function name self.state = state.NAME def process_name(self, ln, line, source): """ STATE_NAME: Looking for the "name - description" line """ # # Check for a DOC: block and handle them specially. # if doc_block.search(line): if not doc_block.group(1): self.entry.begin_section(ln, "Introduction") else: self.entry.begin_section(ln, doc_block.group(1)) self.entry.identifier = self.entry.section self.state = state.DOCBLOCK # # Otherwise we're looking for a normal kerneldoc declaration line. # elif doc_decl.search(line): self.entry.identifier = doc_decl.group(1) # Test for data declaration if doc_begin_data.search(line): self.entry.decl_type = doc_begin_data.group(1) self.entry.identifier = doc_begin_data.group(2) # # Look for a function description # elif doc_begin_func.search(line): self.entry.identifier = doc_begin_func.group(1) self.entry.decl_type = "function" # # We struck out. # else: self.emit_msg(ln, f"This comment starts with '/**', but isn't a kernel-doc comment. Refer to Documentation/doc-guide/kernel-doc.rst\n{line}") self.state = state.NORMAL return # # OK, set up for a new kerneldoc entry. # self.state = state.BODY self.entry.identifier = self.entry.identifier.strip(" ") # if there's no @param blocks need to set up default section here self.entry.begin_section(ln + 1) # # Find the description portion, which *should* be there but # isn't always. # (We should be able to capture this from the previous parsing - someday) # r = KernRe("[-:](.*)") if r.search(line): self.entry.declaration_purpose = trim_whitespace(r.group(1)) self.state = state.DECLARATION else: self.entry.declaration_purpose = "" if not self.entry.declaration_purpose and self.config.wshort_desc: self.emit_msg(ln, f"missing initial short description on line:\n{line}") if not self.entry.identifier and self.entry.decl_type != "enum": self.emit_msg(ln, f"wrong kernel-doc identifier on line:\n{line}") self.state = state.NORMAL if self.config.verbose: self.emit_msg(ln, f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}", warning=False) # # Failed to find an identifier. Emit a warning # else: self.emit_msg(ln, f"Cannot find identifier on line:\n{line}") def is_new_section(self, ln, line): """ Helper function to determine if a new section is being started. """ if doc_sect.search(line): self.state = state.BODY # # Pick out the name of our new section, tweaking it if need be. # newsection = doc_sect.group(1) if newsection.lower() == 'description': newsection = 'Description' elif newsection.lower() == 'context': newsection = 'Context' self.state = state.SPECIAL_SECTION elif newsection.lower() in ["@return", "@returns", "return", "returns"]: newsection = "Return" self.state = state.SPECIAL_SECTION elif newsection[0] == '@': self.state = state.SPECIAL_SECTION # # Initialize the contents, and get the new section going. # newcontents = doc_sect.group(2) if not newcontents: newcontents = "" self.dump_section() self.entry.begin_section(ln, newsection) self.entry.leading_space = None self.entry.add_text(newcontents.lstrip()) return True return False def is_comment_end(self, ln, line): """ Helper function to detect (and effect) the end of a kerneldoc comment. """ if doc_end.search(line): self.dump_section() # Look for doc_com + <text> + doc_end: r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:.]+\*/') if r.match(line): self.emit_msg(ln, f"suspicious ending line: {line}") self.entry.prototype = "" self.entry.new_start_line = ln + 1 self.state = state.PROTO return True return False def process_decl(self, ln, line, source): """ STATE_DECLARATION: We've seen the beginning of a declaration. """ if self.is_new_section(ln, line) or self.is_comment_end(ln, line): return # # Look for anything with the " * " line beginning. # if doc_content.search(line): cont = doc_content.group(1) # # A blank line means that we have moved out of the declaration # part of the comment (without any "special section" parameter # descriptions). # if cont == "": self.state = state.BODY # # Otherwise we have more of the declaration section to soak up. # else: self.entry.declaration_purpose = \ trim_whitespace(self.entry.declaration_purpose + ' ' + cont) else: # Unknown line, ignore self.emit_msg(ln, f"bad line: {line}") def process_special(self, ln, line, source): """ STATE_SPECIAL_SECTION: a section ending with a blank line. """ # # If we have hit a blank line (only the " * " marker), then this # section is done. # if KernRe(r"\s*\*\s*$").match(line): self.entry.begin_section(ln, dump = True) self.state = state.BODY return # # Not a blank line, look for the other ways to end the section. # if self.is_new_section(ln, line) or self.is_comment_end(ln, line): return # # OK, we should have a continuation of the text for this section. # if doc_content.search(line): cont = doc_content.group(1) # # If the lines of text after the first in a special section have # leading white space, we need to trim it out or Sphinx will get # confused. For the second line (the None case), see what we # find there and remember it. # if self.entry.leading_space is None: r = KernRe(r'^(\s+)') if r.match(cont): self.entry.leading_space = len(r.group(1)) else: self.entry.leading_space = 0 # # Otherwise, before trimming any leading chars, be *sure* # that they are white space. We should maybe warn if this # isn't the case. # for i in range(0, self.entry.leading_space): if cont[i] != " ": self.entry.leading_space = i break # # Add the trimmed result to the section and we're done. # self.entry.add_text(cont[self.entry.leading_space:]) else: # Unknown line, ignore self.emit_msg(ln, f"bad line: {line}") def process_body(self, ln, line, source): """ STATE_BODY: the bulk of a kerneldoc comment. """ if self.is_new_section(ln, line) or self.is_comment_end(ln, line): return if doc_content.search(line): cont = doc_content.group(1) self.entry.add_text(cont) else: # Unknown line, ignore self.emit_msg(ln, f"bad line: {line}") def process_inline_name(self, ln, line, source): """STATE_INLINE_NAME: beginning of docbook comments within a prototype.""" if doc_inline_sect.search(line): self.entry.begin_section(ln, doc_inline_sect.group(1)) self.entry.add_text(doc_inline_sect.group(2).lstrip()) self.state = state.INLINE_TEXT elif doc_inline_end.search(line): self.dump_section() self.state = state.PROTO elif doc_content.search(line): self.emit_msg(ln, f"Incorrect use of kernel-doc format: {line}") self.state = state.PROTO # # Don't let it add partial comments at the code, as breaks the # logic meant to remove comments from prototypes. # self.process_proto_type(ln, "/**\n" + line, source) # else ... ?? def process_inline_text(self, ln, line, source): """STATE_INLINE_TEXT: docbook comments within a prototype.""" if doc_inline_end.search(line): self.dump_section() self.state = state.PROTO elif doc_content.search(line): self.entry.add_text(doc_content.group(1)) # else ... ?? def syscall_munge(self, ln, proto): # pylint: disable=W0613 """ Handle syscall definitions. """ is_void = False # Strip newlines/CR's proto = re.sub(r'[\r\n]+', ' ', proto) # Check if it's a SYSCALL_DEFINE0 if 'SYSCALL_DEFINE0' in proto: is_void = True # Replace SYSCALL_DEFINE with correct return type & function name proto = KernRe(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto) r = KernRe(r'long\s+(sys_.*?),') if r.search(proto): proto = KernRe(',').sub('(', proto, count=1) elif is_void: proto = KernRe(r'\)').sub('(void)', proto, count=1) # Now delete all of the odd-numbered commas in the proto # so that argument types & names don't have a comma between them count = 0 length = len(proto) if is_void: length = 0 # skip the loop if is_void for ix in range(length): if proto[ix] == ',': count += 1 if count % 2 == 1: proto = proto[:ix] + ' ' + proto[ix + 1:] return proto def tracepoint_munge(self, ln, proto): """ Handle tracepoint definitions. """ tracepointname = None tracepointargs = None # Match tracepoint name based on different patterns r = KernRe(r'TRACE_EVENT\((.*?),') if r.search(proto): tracepointname = r.group(1) r = KernRe(r'DEFINE_SINGLE_EVENT\((.*?),') if r.search(proto): tracepointname = r.group(1) r = KernRe(r'DEFINE_EVENT\((.*?),(.*?),') if r.search(proto): tracepointname = r.group(2) if tracepointname: tracepointname = tracepointname.lstrip() r = KernRe(r'TP_PROTO\((.*?)\)') if r.search(proto): tracepointargs = r.group(1) if not tracepointname or not tracepointargs: self.emit_msg(ln, f"Unrecognized tracepoint format:\n{proto}\n") else: proto = f"static inline void trace_{tracepointname}({tracepointargs})" self.entry.identifier = f"trace_{self.entry.identifier}" return proto def process_proto_function(self, ln, line, source): """Ancillary routine to process a function prototype.""" # strip C99-style comments to end of line line = KernRe(r"//.*$", re.S).sub('', line) # # Soak up the line's worth of prototype text, stopping at { or ; if present. # if KernRe(r'\s*#\s*define').match(line): self.entry.prototype = line elif not line.startswith('#'): # skip other preprocessor stuff r = KernRe(r'([^\{]*)') if r.match(line): self.entry.prototype += r.group(1) + " " # # If we now have the whole prototype, clean it up and declare victory. # if '{' in line or ';' in line or KernRe(r'\s*#\s*define').match(line): # strip comments and surrounding spaces self.entry.prototype = KernRe(r'/\*.*\*/').sub('', self.entry.prototype).strip() # # Handle self.entry.prototypes for function pointers like: # int (*pcs_config)(struct foo) # by turning it into # int pcs_config(struct foo) # r = KernRe(r'^(\S+\s+)\(\s*\*(\S+)\)') self.entry.prototype = r.sub(r'\1\2', self.entry.prototype) # # Handle special declaration syntaxes # if 'SYSCALL_DEFINE' in self.entry.prototype:Lines 1001–1500 of 1679. Previous lines Load more
return_type = r.group(1) declaration_name = r.group(2) args = r.group(3) self.create_parameter_list(ln, decl_type, args, ',', declaration_name) found = True break # # Parsing done; make sure that things are as we expect. # if not found: self.emit_msg(ln, f"cannot understand function prototype: '{prototype}'") return if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for {self.entry.identifier}(). " f"Prototype was for {declaration_name}() instead") return self.check_sections(ln, declaration_name, "function") self.check_return_section(ln, declaration_name, return_type) # # Store the result. # self.output_declaration(decl_type, declaration_name, source=source, typedef=('typedef' in return_type), functiontype=return_type, purpose=self.entry.declaration_purpose, func_macro=func_macro) def dump_typedef(self, ln, proto, source): """ Store a ``typedef`` inside self.entries array. """ # # We start by looking for function typedefs. # typedef_type = r'typedef((?:\s+[\w*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' typedef_ident = r'\*?\s*(\w\S+)\s*' typedef_args = r'\s*\((.*)\);' source = source typedef1 = KernRe(typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args) typedef2 = KernRe(typedef_type + typedef_ident + typedef_args) # Parse function typedef prototypes for r in [typedef1, typedef2]: if not r.match(proto): continue return_type = r.group(1).strip() declaration_name = r.group(2) args = r.group(3) if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") return self.create_parameter_list(ln, 'function', args, ',', declaration_name) self.output_declaration('function', declaration_name, source=source, typedef=True, functiontype=return_type, purpose=self.entry.declaration_purpose) return # # Not a function, try to parse a simple typedef. # r = KernRe(r'typedef.*\s+(\w+)\s*;') if r.match(proto): declaration_name = r.group(1) if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n") return self.output_declaration('typedef', declaration_name, source=source, purpose=self.entry.declaration_purpose) return self.emit_msg(ln, "error: Cannot parse typedef!") @staticmethod def process_export(function_set, line): """ process ``EXPORT_SYMBOL*`` tags This method doesn't use any variable from the class, so declare it with a staticmethod decorator. """ # We support documenting some exported symbols with different # names. A horrible hack. suffixes = [ '_noprof' ] # Note: it accepts only one EXPORT_SYMBOL* per line, as having # multiple export lines would violate Kernel coding style. if export_symbol.search(line): symbol = export_symbol.group(2) elif export_symbol_ns.search(line): symbol = export_symbol_ns.group(2) else: return False # # Found an export, trim out any special suffixes # for suffix in suffixes: # Be backward compatible with Python < 3.9 if symbol.endswith(suffix): symbol = symbol[:-len(suffix)] function_set.add(symbol) return True def process_normal(self, ln, line, source): """ STATE_NORMAL: looking for the ``/**`` to begin everything. """ if not doc_start.match(line): return # start a new entry self.reset_state(ln) # next line is always the function name self.state = state.NAME def process_name(self, ln, line, source): """ STATE_NAME: Looking for the "name - description" line """ # # Check for a DOC: block and handle them specially. # if doc_block.search(line): if not doc_block.group(1): self.entry.begin_section(ln, "Introduction") else: self.entry.begin_section(ln, doc_block.group(1)) self.entry.identifier = self.entry.section self.state = state.DOCBLOCK # # Otherwise we're looking for a normal kerneldoc declaration line. # elif doc_decl.search(line): self.entry.identifier = doc_decl.group(1) # Test for data declaration if doc_begin_data.search(line): self.entry.decl_type = doc_begin_data.group(1) self.entry.identifier = doc_begin_data.group(2) # # Look for a function description # elif doc_begin_func.search(line): self.entry.identifier = doc_begin_func.group(1) self.entry.decl_type = "function" # # We struck out. # else: self.emit_msg(ln, f"This comment starts with '/**', but isn't a kernel-doc comment. Refer to Documentation/doc-guide/kernel-doc.rst\n{line}") self.state = state.NORMAL return # # OK, set up for a new kerneldoc entry. # self.state = state.BODY self.entry.identifier = self.entry.identifier.strip(" ") # if there's no @param blocks need to set up default section here self.entry.begin_section(ln + 1) # # Find the description portion, which *should* be there but # isn't always. # (We should be able to capture this from the previous parsing - someday) # r = KernRe("[-:](.*)") if r.search(line): self.entry.declaration_purpose = trim_whitespace(r.group(1)) self.state = state.DECLARATION else: self.entry.declaration_purpose = "" if not self.entry.declaration_purpose and self.config.wshort_desc: self.emit_msg(ln, f"missing initial short description on line:\n{line}") if not self.entry.identifier and self.entry.decl_type != "enum": self.emit_msg(ln, f"wrong kernel-doc identifier on line:\n{line}") self.state = state.NORMAL if self.config.verbose: self.emit_msg(ln, f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}", warning=False) # # Failed to find an identifier. Emit a warning # else: self.emit_msg(ln, f"Cannot find identifier on line:\n{line}") def is_new_section(self, ln, line): """ Helper function to determine if a new section is being started. """ if doc_sect.search(line): self.state = state.BODY # # Pick out the name of our new section, tweaking it if need be. # newsection = doc_sect.group(1) if newsection.lower() == 'description': newsection = 'Description' elif newsection.lower() == 'context': newsection = 'Context' self.state = state.SPECIAL_SECTION elif newsection.lower() in ["@return", "@returns", "return", "returns"]: newsection = "Return" self.state = state.SPECIAL_SECTION elif newsection[0] == '@': self.state = state.SPECIAL_SECTION # # Initialize the contents, and get the new section going. # newcontents = doc_sect.group(2) if not newcontents: newcontents = "" self.dump_section() self.entry.begin_section(ln, newsection) self.entry.leading_space = None self.entry.add_text(newcontents.lstrip()) return True return False def is_comment_end(self, ln, line): """ Helper function to detect (and effect) the end of a kerneldoc comment. """ if doc_end.search(line): self.dump_section() # Look for doc_com + <text> + doc_end: r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:.]+\*/') if r.match(line): self.emit_msg(ln, f"suspicious ending line: {line}") self.entry.prototype = "" self.entry.new_start_line = ln + 1 self.state = state.PROTO return True return False def process_decl(self, ln, line, source): """ STATE_DECLARATION: We've seen the beginning of a declaration. """ if self.is_new_section(ln, line) or self.is_comment_end(ln, line): return # # Look for anything with the " * " line beginning. # if doc_content.search(line): cont = doc_content.group(1) # # A blank line means that we have moved out of the declaration # part of the comment (without any "special section" parameter # descriptions). # if cont == "": self.state = state.BODY # # Otherwise we have more of the declaration section to soak up. # else: self.entry.declaration_purpose = \ trim_whitespace(self.entry.declaration_purpose + ' ' + cont) else: # Unknown line, ignore self.emit_msg(ln, f"bad line: {line}") def process_special(self, ln, line, source): """ STATE_SPECIAL_SECTION: a section ending with a blank line. """ # # If we have hit a blank line (only the " * " marker), then this # section is done. # if KernRe(r"\s*\*\s*$").match(line): self.entry.begin_section(ln, dump = True) self.state = state.BODY return # # Not a blank line, look for the other ways to end the section. # if self.is_new_section(ln, line) or self.is_comment_end(ln, line): return # # OK, we should have a continuation of the text for this section. # if doc_content.search(line): cont = doc_content.group(1) # # If the lines of text after the first in a special section have # leading white space, we need to trim it out or Sphinx will get # confused. For the second line (the None case), see what we # find there and remember it. # if self.entry.leading_space is None: r = KernRe(r'^(\s+)') if r.match(cont): self.entry.leading_space = len(r.group(1)) else: self.entry.leading_space = 0 # # Otherwise, before trimming any leading chars, be *sure* # that they are white space. We should maybe warn if this # isn't the case. # for i in range(0, self.entry.leading_space): if cont[i] != " ": self.entry.leading_space = i break # # Add the trimmed result to the section and we're done. # self.entry.add_text(cont[self.entry.leading_space:]) else: # Unknown line, ignore self.emit_msg(ln, f"bad line: {line}") def process_body(self, ln, line, source): """ STATE_BODY: the bulk of a kerneldoc comment. """ if self.is_new_section(ln, line) or self.is_comment_end(ln, line): return if doc_content.search(line): cont = doc_content.group(1) self.entry.add_text(cont) else: # Unknown line, ignore self.emit_msg(ln, f"bad line: {line}") def process_inline_name(self, ln, line, source): """STATE_INLINE_NAME: beginning of docbook comments within a prototype.""" if doc_inline_sect.search(line): self.entry.begin_section(ln, doc_inline_sect.group(1)) self.entry.add_text(doc_inline_sect.group(2).lstrip()) self.state = state.INLINE_TEXT elif doc_inline_end.search(line): self.dump_section() self.state = state.PROTO elif doc_content.search(line): self.emit_msg(ln, f"Incorrect use of kernel-doc format: {line}") self.state = state.PROTO # # Don't let it add partial comments at the code, as breaks the # logic meant to remove comments from prototypes. # self.process_proto_type(ln, "/**\n" + line, source) # else ... ?? def process_inline_text(self, ln, line, source): """STATE_INLINE_TEXT: docbook comments within a prototype.""" if doc_inline_end.search(line): self.dump_section() self.state = state.PROTO elif doc_content.search(line): self.entry.add_text(doc_content.group(1)) # else ... ?? def syscall_munge(self, ln, proto): # pylint: disable=W0613 """ Handle syscall definitions. """ is_void = False # Strip newlines/CR's proto = re.sub(r'[\r\n]+', ' ', proto) # Check if it's a SYSCALL_DEFINE0 if 'SYSCALL_DEFINE0' in proto: is_void = True # Replace SYSCALL_DEFINE with correct return type & function name proto = KernRe(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto) r = KernRe(r'long\s+(sys_.*?),') if r.search(proto): proto = KernRe(',').sub('(', proto, count=1) elif is_void: proto = KernRe(r'\)').sub('(void)', proto, count=1) # Now delete all of the odd-numbered commas in the proto # so that argument types & names don't have a comma between them count = 0 length = len(proto) if is_void: length = 0 # skip the loop if is_void for ix in range(length): if proto[ix] == ',': count += 1 if count % 2 == 1: proto = proto[:ix] + ' ' + proto[ix + 1:] return proto def tracepoint_munge(self, ln, proto): """ Handle tracepoint definitions. """ tracepointname = None tracepointargs = None # Match tracepoint name based on different patterns r = KernRe(r'TRACE_EVENT\((.*?),') if r.search(proto): tracepointname = r.group(1) r = KernRe(r'DEFINE_SINGLE_EVENT\((.*?),') if r.search(proto): tracepointname = r.group(1) r = KernRe(r'DEFINE_EVENT\((.*?),(.*?),') if r.search(proto): tracepointname = r.group(2) if tracepointname: tracepointname = tracepointname.lstrip() r = KernRe(r'TP_PROTO\((.*?)\)') if r.search(proto): tracepointargs = r.group(1) if not tracepointname or not tracepointargs: self.emit_msg(ln, f"Unrecognized tracepoint format:\n{proto}\n") else: proto = f"static inline void trace_{tracepointname}({tracepointargs})" self.entry.identifier = f"trace_{self.entry.identifier}" return proto def process_proto_function(self, ln, line, source): """Ancillary routine to process a function prototype.""" # strip C99-style comments to end of line line = KernRe(r"//.*$", re.S).sub('', line) # # Soak up the line's worth of prototype text, stopping at { or ; if present. # if KernRe(r'\s*#\s*define').match(line): self.entry.prototype = line elif not line.startswith('#'): # skip other preprocessor stuff r = KernRe(r'([^\{]*)') if r.match(line): self.entry.prototype += r.group(1) + " " # # If we now have the whole prototype, clean it up and declare victory. # if '{' in line or ';' in line or KernRe(r'\s*#\s*define').match(line): # strip comments and surrounding spaces self.entry.prototype = KernRe(r'/\*.*\*/').sub('', self.entry.prototype).strip() # # Handle self.entry.prototypes for function pointers like: # int (*pcs_config)(struct foo) # by turning it into # int pcs_config(struct foo) # r = KernRe(r'^(\S+\s+)\(\s*\*(\S+)\)') self.entry.prototype = r.sub(r'\1\2', self.entry.prototype) # # Handle special declaration syntaxes # if 'SYSCALL_DEFINE' in self.entry.prototype: