""" if self.entry.anon_struct_union and dtype == "" and param == "}": return # Ignore the ending }; from anonymous struct/union self.entry.anon_struct_union = False param = KernRe(r'[\[\)].*').sub('', param, count=1) # # Look at various "anonymous type" cases. # if dtype == '': if param.endswith("..."): if len(param) > 3: # there is a name provided, use that param = param[:-3] if not self.entry.parameterdescs.get(param): self.entry.parameterdescs[param] = "variable arguments" elif (not param) or param == "void": param = "void" self.entry.parameterdescs[param] = "no arguments" elif param in ["struct", "union"]: # Handle unnamed (anonymous) union or struct dtype = param param = "{unnamed_" + param + "}" self.entry.parameterdescs[param] = "anonymous\n" self.entry.anon_struct_union = True # Warn if parameter has no description # (but ignore ones starting with # as these are not parameters # but inline preprocessor statements) if param not in self.entry.parameterdescs and not param.startswith("#"): self.entry.parameterdescs[param] = self.undescribed if "." not in param: if decl_type == 'function': dname = f"{decl_type} parameter" else: dname = f"{decl_type} member" self.emit_msg(ln, f"{dname} '{param}' not described in '{declaration_name}'") # Strip spaces from param so that it is one continuous string on # parameterlist. This fixes a problem where check_sections() # cannot find a parameter like "addr[6 + 2]" because it actually # appears as "addr[6", "+", "2]" on the parameter list. # However, it's better to maintain the param string unchanged for # output, so just weaken the string compare in check_sections() # to ignore "[blah" in a parameter string. self.entry.parameterlist.append(param) org_arg = KernRe(r'\s\s+').sub(' ', org_arg) self.entry.parametertypes[param] = org_arg def create_parameter_list(self, ln, decl_type, args, splitter, declaration_name): """ Creates a list of parameters, storing them at self.entry. """ # temporarily replace all commas inside function pointer definition arg_expr = KernRe(r'(\([^\),]+),') while arg_expr.search(args): args = arg_expr.sub(r"\1#", args) for arg in args.split(splitter): # Ignore argument attributes arg = KernRe(r'\sPOS0?\s').sub(' ', arg) # Strip leading/trailing spaces arg = arg.strip() arg = KernRe(r'\s+').sub(' ', arg, count=1) if arg.startswith('#'): # Treat preprocessor directive as a typeless variable just to fill # corresponding data structures "correctly". Catch it later in # output_* subs. # Treat preprocessor directive as a typeless variable self.push_parameter(ln, decl_type, arg, "", "", declaration_name) # # The pointer-to-function case. # elif KernRe(r'\(.+\)\s*\(').search(arg): arg = arg.replace('#', ',') r = KernRe(r'[^\(]+\(\*?\s*' # Everything up to "(*" r'([\w\[\].]*)' # Capture the name and possible [array] r'\s*\)') # Make sure the trailing ")" is there if r.match(arg): param = r.group(1) else: self.emit_msg(ln, f"Invalid param: {arg}") param = arg dtype = arg.replace(param, '') self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) # # The array-of-pointers case. Dig the parameter name out from the middle # of the declaration. # elif KernRe(r'\(.+\)\s*\[').search(arg): r = KernRe(r'[^\(]+\(\s*\*\s*' # Up to "(" and maybe "*" r'([\w.]*?)' # The actual pointer name r'\s*(\[\s*\w+\s*\]\s*)*\)') # The [array portion] if r.match(arg): param = r.group(1) else: self.emit_msg(ln, f"Invalid param: {arg}") param = arg dtype = arg.replace(param, '') self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) elif arg: # # Clean up extraneous spaces and split the string at commas; the first # element of the resulting list will also include the type information. # arg = KernRe(r'\s*:\s*').sub(":", arg) arg = KernRe(r'\s*\[').sub('[', arg) args = KernRe(r'\s*,\s*').split(arg) args[0] = re.sub(r'(\*+)\s*', r' \1', args[0]) # # args[0] has a string of "type a". If "a" includes an [array] # declaration, we want to not be fooled by any white space inside # the brackets, so detect and handle that case specially. # r = KernRe(r'^([^[\]]*\s+)(.*)$') if r.match(args[0]): args[0] = r.group(2) dtype = r.group(1) else: # No space in args[0]; this seems wrong but preserves previous behavior dtype = '' bitfield_re = KernRe(r'(.*?):(\w+)') for param in args: # # For pointers, shift the star(s) from the variable name to the # type declaration. # r = KernRe(r'^(\*+)\s*(.*)') if r.match(param): self.push_parameter(ln, decl_type, r.group(2), f"{dtype} {r.group(1)}", arg, declaration_name) # # Perform a similar shift for bitfields. # elif bitfield_re.search(param): if dtype != "": # Skip unnamed bit-fields self.push_parameter(ln, decl_type, bitfield_re.group(1), f"{dtype}:{bitfield_re.group(2)}", arg, declaration_name) else: self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) def check_sections(self, ln, decl_name, decl_type): """ Check for errors inside sections, emitting warnings if not found parameters are described. """ for section in self.entry.sections: if section not in self.entry.parameterlist and \ not known_sections.search(section): if decl_type == 'function': dname = f"{decl_type} parameter" else: dname = f"{decl_type} member" self.emit_msg(ln, f"Excess {dname} '{section}' description in '{decl_name}'") def check_return_section(self, ln, declaration_name, return_type): """ If the function doesn't return void, warns about the lack of a return description. """ if not self.config.wreturn: return # Ignore an empty return type (It's a macro) # Ignore functions with a "void" return type (but not "void *") if not return_type or KernRe(r'void\s*\w*\s*$').search(return_type): return if not self.entry.sections.get("Return", None): self.emit_msg(ln, f"No description found for return value of '{declaration_name}'") def split_struct_proto(self, proto): """ Split apart a structure prototype; returns (struct|union, name, members) or ``None``. """ type_pattern = r'(struct|union)' qualifiers = [ "__attribute__", "__packed", "__aligned", "____cacheline_aligned_in_smp", "____cacheline_aligned", ] definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?" r = KernRe(type_pattern + r'\s+(\w+)\s*' + definition_body) if r.search(proto): return (r.group(1), r.group(2), r.group(3)) else: r = KernRe(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;') if r.search(proto): return (r.group(1), r.group(3), r.group(2)) return None def rewrite_struct_members(self, members): """ Process ``struct``/``union`` members from the most deeply nested outward. Rewrite the members of a ``struct`` or ``union`` for easier formatting later on. Among other things, this function will turn a member like:: struct { inner_members; } foo; into:: struct foo; inner_members; """ # # The trick is in the ``^{`` below - it prevents a match of an outer # ``struct``/``union`` until the inner one has been munged # (removing the ``{`` in the process). # struct_members = KernRe(r'(struct|union)' # 0: declaration type r'([^\{\};]+)' # 1: possible name r'(\{)' r'([^\{\}]*)' # 3: Contents of declaration r'(\})' r'([^\{\};]*)(;)') # 5: Remaining stuff after declaration tuples = struct_members.findall(members) while tuples: for t in tuples: newmember = "" oldmember = "".join(t) # Reconstruct the original formatting dtype, name, lbr, content, rbr, rest, semi = t # # Pass through each field name, normalizing the form and formatting. # for s_id in rest.split(','): s_id = s_id.strip() newmember += f"{dtype} {s_id}; " # # Remove bitfield/array/pointer info, getting the bare name. # s_id = KernRe(r'[:\[].*').sub('', s_id) s_id = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', s_id) # # Pass through the members of this inner structure/union. # for arg in content.split(';'): arg = arg.strip() # # Look for (type)(*name)(args) - pointer to function # r = KernRe(r'^([^\(]+\(\*?\s*)([\w.]*)(\s*\).*)') if r.match(arg): dtype, name, extra = r.group(1), r.group(2), r.group(3) # Pointer-to-function if not s_id: # Anonymous struct/union newmember += f"{dtype}{name}{extra}; " else: newmember += f"{dtype}{s_id}.{name}{extra}; " # # Otherwise a non-function member. # else: # # Remove bitmap and array portions and spaces around commas # arg = KernRe(r':\s*\d+\s*').sub('', arg) arg = KernRe(r'\[.*\]').sub('', arg) arg = KernRe(r'\s*,\s*').sub(',', arg) # # Look for a normal decl - "type name[,name...]" # r = KernRe(r'(.*)\s+([\S+,]+)') if r.search(arg): for name in r.group(2).split(','): name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name) if not s_id: # Anonymous struct/union newmember += f"{r.group(1)} {name}; " else: newmember += f"{r.group(1)} {s_id}.{name}; " else: newmember += f"{arg}; " # # At the end of the s_id loop, replace the original declaration with # the munged version. # members = members.replace(oldmember, newmember) # # End of the tuple loop - search again and see if there are outer members # that now turn up. # tuples = struct_members.findall(members) return members def format_struct_decl(self, declaration): """ Format the ``struct`` declaration into a standard form for inclusion in the resulting docs. """ # # Insert newlines, get rid of extra spaces. # declaration = KernRe(r'([\{;])').sub(r'\1\n', declaration) declaration = KernRe(r'\}\s+;').sub('};', declaration) # # Format inline enums with each member on its own line. # r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') while r.search(declaration): declaration = r.sub(r'\1,\n\2', declaration) # # Now go through and supply the right number of tabs # for each line. # def_args = declaration.split('\n') level = 1 declaration = "" for clause in def_args: clause = KernRe(r'\s+').sub(' ', clause.strip(), count=1) if clause: if '}' in clause and level > 1: level -= 1 if not clause.startswith('#'): declaration += "\t" * level declaration += "\t" + clause + "\n" if "{" in clause and "}" not in clause: level += 1 return declaration def dump_struct(self, ln, proto): """ Store an entry for a ``struct`` or ``union`` """ # # Do the basic parse to get the pieces of the declaration. # struct_parts = self.split_struct_proto(proto) if not struct_parts: self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") return decl_type, declaration_name, members = struct_parts if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. " f"Prototype was for {decl_type} {declaration_name} instead\n") return # # Go through the list of members applying all of our transformations. # members = trim_private_members(members) members = apply_transforms(struct_xforms, members) nested = NestedMatch() for search, sub in struct_nested_prefixes: members = nested.sub(search, sub, members) # # Deal with embedded struct and union members, and drop enums entirely. # declaration = members members = self.rewrite_struct_members(members) members = re.sub(r'(\{[^\{\}]*\})', '', members) # # Output the result and we are done. # self.create_parameter_list(ln, decl_type, members, ';', declaration_name) self.check_sections(ln, declaration_name, decl_type) self.output_declaration(decl_type, declaration_name, definition=self.format_struct_decl(declaration), purpose=self.entry.declaration_purpose) def dump_enum(self, ln, proto): """ Store an ``enum`` inside self.entries array. """ # # Strip preprocessor directives. Note that this depends on the # trailing semicolon we added in process_proto_type(). # proto = KernRe(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto) # # Parse out the name and members of the enum. Typedef form first. # r = KernRe(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;') if r.search(proto): declaration_name = r.group(2) members = trim_private_members(r.group(1)) # # Failing that, look for a straight enum # else: r = KernRe(r'enum\s+(\w*)\s*\{(.*)\}') if r.match(proto): declaration_name = r.group(1) members = trim_private_members(r.group(2)) # # OK, this isn't going to work. # else: self.emit_msg(ln, f"{proto}: error: Cannot parse enum!") return # # Make sure we found what we were expecting. # if self.entry.identifier != declaration_name: if self.entry.identifier == "": self.emit_msg(ln, f"{proto}: wrong kernel-doc identifier on prototype") else: self.emit_msg(ln, f"expecting prototype for enum {self.entry.identifier}. " f"Prototype was for enum {declaration_name} instead") return if not declaration_name: declaration_name = "(anonymous)" # # Parse out the name of each enum member, and verify that we # have a description for it. # member_set = set() members = KernRe(r'\([^;)]*\)').sub('', members) for arg in members.split(','): if not arg: continue arg = KernRe(r'^\s*(\w+).*').sub(r'\1', arg) self.entry.parameterlist.append(arg) if arg not in self.entry.parameterdescs: self.entry.parameterdescs[arg] = self.undescribed self.emit_msg(ln, f"Enum value '{arg}' not described in enum '{declaration_name}'") member_set.add(arg) # # Ensure that every described member actually exists in the enum. # for k in self.entry.parameterdescs: if k not in member_set: self.emit_msg(ln, f"Excess enum value '@{k}' description in '{declaration_name}'") self.output_declaration('enum', declaration_name, purpose=self.entry.declaration_purpose) def dump_var(self, ln, proto): """ Store variables that are part of kAPI. """ VAR_ATTRIBS = [ "extern", ] OPTIONAL_VAR_ATTR = "^(?:" + "|".join(VAR_ATTRIBS) + ")?" sub_prefixes = [ (KernRe(r"__read_mostly"), ""), (KernRe(r"__ro_after_init"), ""), (KernRe(r"(?://.*)$"), ""), (KernRe(r"(?:/\*.*\*/)"), ""), (KernRe(r";$"), ""), (KernRe(r"=.*"), ""), ] # # Store the full prototype before modifying it # full_proto = proto declaration_name = None # # Handle macro definitions # macro_prefixes = [ KernRe(r"DEFINE_[\w_]+\s*\(([\w_]+)\)"), ] for r in macro_prefixes: match = r.search(proto) if match: declaration_name = match.group(1)Lines 501–1000 of 1784. Previous lines Load more
""" if self.entry.anon_struct_union and dtype == "" and param == "}": return # Ignore the ending }; from anonymous struct/union self.entry.anon_struct_union = False param = KernRe(r'[\[\)].*').sub('', param, count=1) # # Look at various "anonymous type" cases. # if dtype == '': if param.endswith("..."): if len(param) > 3: # there is a name provided, use that param = param[:-3] if not self.entry.parameterdescs.get(param): self.entry.parameterdescs[param] = "variable arguments" elif (not param) or param == "void": param = "void" self.entry.parameterdescs[param] = "no arguments" elif param in ["struct", "union"]: # Handle unnamed (anonymous) union or struct dtype = param param = "{unnamed_" + param + "}" self.entry.parameterdescs[param] = "anonymous\n" self.entry.anon_struct_union = True # Warn if parameter has no description # (but ignore ones starting with # as these are not parameters # but inline preprocessor statements) if param not in self.entry.parameterdescs and not param.startswith("#"): self.entry.parameterdescs[param] = self.undescribed if "." not in param: if decl_type == 'function': dname = f"{decl_type} parameter" else: dname = f"{decl_type} member" self.emit_msg(ln, f"{dname} '{param}' not described in '{declaration_name}'") # Strip spaces from param so that it is one continuous string on # parameterlist. This fixes a problem where check_sections() # cannot find a parameter like "addr[6 + 2]" because it actually # appears as "addr[6", "+", "2]" on the parameter list. # However, it's better to maintain the param string unchanged for # output, so just weaken the string compare in check_sections() # to ignore "[blah" in a parameter string. self.entry.parameterlist.append(param) org_arg = KernRe(r'\s\s+').sub(' ', org_arg) self.entry.parametertypes[param] = org_arg def create_parameter_list(self, ln, decl_type, args, splitter, declaration_name): """ Creates a list of parameters, storing them at self.entry. """ # temporarily replace all commas inside function pointer definition arg_expr = KernRe(r'(\([^\),]+),') while arg_expr.search(args): args = arg_expr.sub(r"\1#", args) for arg in args.split(splitter): # Ignore argument attributes arg = KernRe(r'\sPOS0?\s').sub(' ', arg) # Strip leading/trailing spaces arg = arg.strip() arg = KernRe(r'\s+').sub(' ', arg, count=1) if arg.startswith('#'): # Treat preprocessor directive as a typeless variable just to fill # corresponding data structures "correctly". Catch it later in # output_* subs. # Treat preprocessor directive as a typeless variable self.push_parameter(ln, decl_type, arg, "", "", declaration_name) # # The pointer-to-function case. # elif KernRe(r'\(.+\)\s*\(').search(arg): arg = arg.replace('#', ',') r = KernRe(r'[^\(]+\(\*?\s*' # Everything up to "(*" r'([\w\[\].]*)' # Capture the name and possible [array] r'\s*\)') # Make sure the trailing ")" is there if r.match(arg): param = r.group(1) else: self.emit_msg(ln, f"Invalid param: {arg}") param = arg dtype = arg.replace(param, '') self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) # # The array-of-pointers case. Dig the parameter name out from the middle # of the declaration. # elif KernRe(r'\(.+\)\s*\[').search(arg): r = KernRe(r'[^\(]+\(\s*\*\s*' # Up to "(" and maybe "*" r'([\w.]*?)' # The actual pointer name r'\s*(\[\s*\w+\s*\]\s*)*\)') # The [array portion] if r.match(arg): param = r.group(1) else: self.emit_msg(ln, f"Invalid param: {arg}") param = arg dtype = arg.replace(param, '') self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) elif arg: # # Clean up extraneous spaces and split the string at commas; the first # element of the resulting list will also include the type information. # arg = KernRe(r'\s*:\s*').sub(":", arg) arg = KernRe(r'\s*\[').sub('[', arg) args = KernRe(r'\s*,\s*').split(arg) args[0] = re.sub(r'(\*+)\s*', r' \1', args[0]) # # args[0] has a string of "type a". If "a" includes an [array] # declaration, we want to not be fooled by any white space inside # the brackets, so detect and handle that case specially. # r = KernRe(r'^([^[\]]*\s+)(.*)$') if r.match(args[0]): args[0] = r.group(2) dtype = r.group(1) else: # No space in args[0]; this seems wrong but preserves previous behavior dtype = '' bitfield_re = KernRe(r'(.*?):(\w+)') for param in args: # # For pointers, shift the star(s) from the variable name to the # type declaration. # r = KernRe(r'^(\*+)\s*(.*)') if r.match(param): self.push_parameter(ln, decl_type, r.group(2), f"{dtype} {r.group(1)}", arg, declaration_name) # # Perform a similar shift for bitfields. # elif bitfield_re.search(param): if dtype != "": # Skip unnamed bit-fields self.push_parameter(ln, decl_type, bitfield_re.group(1), f"{dtype}:{bitfield_re.group(2)}", arg, declaration_name) else: self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) def check_sections(self, ln, decl_name, decl_type): """ Check for errors inside sections, emitting warnings if not found parameters are described. """ for section in self.entry.sections: if section not in self.entry.parameterlist and \ not known_sections.search(section): if decl_type == 'function': dname = f"{decl_type} parameter" else: dname = f"{decl_type} member" self.emit_msg(ln, f"Excess {dname} '{section}' description in '{decl_name}'") def check_return_section(self, ln, declaration_name, return_type): """ If the function doesn't return void, warns about the lack of a return description. """ if not self.config.wreturn: return # Ignore an empty return type (It's a macro) # Ignore functions with a "void" return type (but not "void *") if not return_type or KernRe(r'void\s*\w*\s*$').search(return_type): return if not self.entry.sections.get("Return", None): self.emit_msg(ln, f"No description found for return value of '{declaration_name}'") def split_struct_proto(self, proto): """ Split apart a structure prototype; returns (struct|union, name, members) or ``None``. """ type_pattern = r'(struct|union)' qualifiers = [ "__attribute__", "__packed", "__aligned", "____cacheline_aligned_in_smp", "____cacheline_aligned", ] definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?" r = KernRe(type_pattern + r'\s+(\w+)\s*' + definition_body) if r.search(proto): return (r.group(1), r.group(2), r.group(3)) else: r = KernRe(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;') if r.search(proto): return (r.group(1), r.group(3), r.group(2)) return None def rewrite_struct_members(self, members): """ Process ``struct``/``union`` members from the most deeply nested outward. Rewrite the members of a ``struct`` or ``union`` for easier formatting later on. Among other things, this function will turn a member like:: struct { inner_members; } foo; into:: struct foo; inner_members; """ # # The trick is in the ``^{`` below - it prevents a match of an outer # ``struct``/``union`` until the inner one has been munged # (removing the ``{`` in the process). # struct_members = KernRe(r'(struct|union)' # 0: declaration type r'([^\{\};]+)' # 1: possible name r'(\{)' r'([^\{\}]*)' # 3: Contents of declaration r'(\})' r'([^\{\};]*)(;)') # 5: Remaining stuff after declaration tuples = struct_members.findall(members) while tuples: for t in tuples: newmember = "" oldmember = "".join(t) # Reconstruct the original formatting dtype, name, lbr, content, rbr, rest, semi = t # # Pass through each field name, normalizing the form and formatting. # for s_id in rest.split(','): s_id = s_id.strip() newmember += f"{dtype} {s_id}; " # # Remove bitfield/array/pointer info, getting the bare name. # s_id = KernRe(r'[:\[].*').sub('', s_id) s_id = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', s_id) # # Pass through the members of this inner structure/union. # for arg in content.split(';'): arg = arg.strip() # # Look for (type)(*name)(args) - pointer to function # r = KernRe(r'^([^\(]+\(\*?\s*)([\w.]*)(\s*\).*)') if r.match(arg): dtype, name, extra = r.group(1), r.group(2), r.group(3) # Pointer-to-function if not s_id: # Anonymous struct/union newmember += f"{dtype}{name}{extra}; " else: newmember += f"{dtype}{s_id}.{name}{extra}; " # # Otherwise a non-function member. # else: # # Remove bitmap and array portions and spaces around commas # arg = KernRe(r':\s*\d+\s*').sub('', arg) arg = KernRe(r'\[.*\]').sub('', arg) arg = KernRe(r'\s*,\s*').sub(',', arg) # # Look for a normal decl - "type name[,name...]" # r = KernRe(r'(.*)\s+([\S+,]+)') if r.search(arg): for name in r.group(2).split(','): name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name) if not s_id: # Anonymous struct/union newmember += f"{r.group(1)} {name}; " else: newmember += f"{r.group(1)} {s_id}.{name}; " else: newmember += f"{arg}; " # # At the end of the s_id loop, replace the original declaration with # the munged version. # members = members.replace(oldmember, newmember) # # End of the tuple loop - search again and see if there are outer members # that now turn up. # tuples = struct_members.findall(members) return members def format_struct_decl(self, declaration): """ Format the ``struct`` declaration into a standard form for inclusion in the resulting docs. """ # # Insert newlines, get rid of extra spaces. # declaration = KernRe(r'([\{;])').sub(r'\1\n', declaration) declaration = KernRe(r'\}\s+;').sub('};', declaration) # # Format inline enums with each member on its own line. # r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') while r.search(declaration): declaration = r.sub(r'\1,\n\2', declaration) # # Now go through and supply the right number of tabs # for each line. # def_args = declaration.split('\n') level = 1 declaration = "" for clause in def_args: clause = KernRe(r'\s+').sub(' ', clause.strip(), count=1) if clause: if '}' in clause and level > 1: level -= 1 if not clause.startswith('#'): declaration += "\t" * level declaration += "\t" + clause + "\n" if "{" in clause and "}" not in clause: level += 1 return declaration def dump_struct(self, ln, proto): """ Store an entry for a ``struct`` or ``union`` """ # # Do the basic parse to get the pieces of the declaration. # struct_parts = self.split_struct_proto(proto) if not struct_parts: self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") return decl_type, declaration_name, members = struct_parts if self.entry.identifier != declaration_name: self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. " f"Prototype was for {decl_type} {declaration_name} instead\n") return # # Go through the list of members applying all of our transformations. # members = trim_private_members(members) members = apply_transforms(struct_xforms, members) nested = NestedMatch() for search, sub in struct_nested_prefixes: members = nested.sub(search, sub, members) # # Deal with embedded struct and union members, and drop enums entirely. # declaration = members members = self.rewrite_struct_members(members) members = re.sub(r'(\{[^\{\}]*\})', '', members) # # Output the result and we are done. # self.create_parameter_list(ln, decl_type, members, ';', declaration_name) self.check_sections(ln, declaration_name, decl_type) self.output_declaration(decl_type, declaration_name, definition=self.format_struct_decl(declaration), purpose=self.entry.declaration_purpose) def dump_enum(self, ln, proto): """ Store an ``enum`` inside self.entries array. """ # # Strip preprocessor directives. Note that this depends on the # trailing semicolon we added in process_proto_type(). # proto = KernRe(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto) # # Parse out the name and members of the enum. Typedef form first. # r = KernRe(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;') if r.search(proto): declaration_name = r.group(2) members = trim_private_members(r.group(1)) # # Failing that, look for a straight enum # else: r = KernRe(r'enum\s+(\w*)\s*\{(.*)\}') if r.match(proto): declaration_name = r.group(1) members = trim_private_members(r.group(2)) # # OK, this isn't going to work. # else: self.emit_msg(ln, f"{proto}: error: Cannot parse enum!") return # # Make sure we found what we were expecting. # if self.entry.identifier != declaration_name: if self.entry.identifier == "": self.emit_msg(ln, f"{proto}: wrong kernel-doc identifier on prototype") else: self.emit_msg(ln, f"expecting prototype for enum {self.entry.identifier}. " f"Prototype was for enum {declaration_name} instead") return if not declaration_name: declaration_name = "(anonymous)" # # Parse out the name of each enum member, and verify that we # have a description for it. # member_set = set() members = KernRe(r'\([^;)]*\)').sub('', members) for arg in members.split(','): if not arg: continue arg = KernRe(r'^\s*(\w+).*').sub(r'\1', arg) self.entry.parameterlist.append(arg) if arg not in self.entry.parameterdescs: self.entry.parameterdescs[arg] = self.undescribed self.emit_msg(ln, f"Enum value '{arg}' not described in enum '{declaration_name}'") member_set.add(arg) # # Ensure that every described member actually exists in the enum. # for k in self.entry.parameterdescs: if k not in member_set: self.emit_msg(ln, f"Excess enum value '@{k}' description in '{declaration_name}'") self.output_declaration('enum', declaration_name, purpose=self.entry.declaration_purpose) def dump_var(self, ln, proto): """ Store variables that are part of kAPI. """ VAR_ATTRIBS = [ "extern", ] OPTIONAL_VAR_ATTR = "^(?:" + "|".join(VAR_ATTRIBS) + ")?" sub_prefixes = [ (KernRe(r"__read_mostly"), ""), (KernRe(r"__ro_after_init"), ""), (KernRe(r"(?://.*)$"), ""), (KernRe(r"(?:/\*.*\*/)"), ""), (KernRe(r";$"), ""), (KernRe(r"=.*"), ""), ] # # Store the full prototype before modifying it # full_proto = proto declaration_name = None # # Handle macro definitions # macro_prefixes = [ KernRe(r"DEFINE_[\w_]+\s*\(([\w_]+)\)"), ] for r in macro_prefixes: match = r.search(proto) if match: declaration_name = match.group(1)