1784 lines · 64.6 KB · Python
RawDownload
        """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):        """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:                self.entry.prototype = self.syscall_munge(ln,                                                          self.entry.prototype)            else:                r = KernRe(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')                if r.search(self.entry.prototype):                    self.entry.prototype = self.tracepoint_munge(ln,                                                                 self.entry.prototype)            #            # ... and we're done            #            self.dump_function(ln, self.entry.prototype)            self.reset_state(ln)     def process_proto_type(self, ln, line):        """        Ancillary routine to process a type.        """         # Strip C99-style comments and surrounding whitespace        line = KernRe(r"//.*$", re.S).sub('', line).strip()        if not line:            return # nothing to see here         # To distinguish preprocessor directive from regular declaration later.        if line.startswith('#'):            line += ";"        #        # Split the declaration on any of { } or ;, and accumulate pieces        # until we hit a semicolon while not inside {brackets}        #        r = KernRe(r'(.*?)([{};])')        for chunk in r.split(line):            if chunk:  # Ignore empty matches                self.entry.prototype += chunk                #                # This cries out for a match statement ... someday after we can                # drop Python 3.9 ...                #                if chunk == '{':                    self.entry.brcount += 1                elif chunk == '}':                    self.entry.brcount -= 1                elif chunk == ';' and self.entry.brcount <= 0:                    self.dump_declaration(ln, self.entry.prototype)                    self.reset_state(ln)                    return        #        # We hit the end of the line while still in the declaration; put        # in a space to represent the newline.        #        self.entry.prototype += ' '     def process_proto(self, ln, line):        """STATE_PROTO: reading a function/whatever prototype."""         if doc_inline_oneline.search(line):            self.entry.begin_section(ln, doc_inline_oneline.group(1))            self.entry.add_text(doc_inline_oneline.group(2))            self.dump_section()         elif doc_inline_start.search(line):            self.state = state.INLINE_NAME         elif self.entry.decl_type == 'function':            self.process_proto_function(ln, line)         else:            self.process_proto_type(ln, line)     def process_docblock(self, ln, line):        """STATE_DOCBLOCK: within a ``DOC:`` block."""         if doc_end.search(line):            self.dump_section()            self.output_declaration("doc", self.entry.identifier)            self.reset_state(ln)         elif doc_content.search(line):            self.entry.add_text(doc_content.group(1))     def parse_export(self):        """        Parses ``EXPORT_SYMBOL*`` macros from a single Kernel source file.        """         export_table = set()         try:            with open(self.fname, "r", encoding="utf8",                      errors="backslashreplace") as fp:                 for line in fp:                    self.process_export(export_table, line)         except IOError:            return None         return export_table     #: The state/action table telling us which function to invoke in each state.    state_actions = {        state.NORMAL:			process_normal,        state.NAME:			process_name,        state.BODY:			process_body,        state.DECLARATION:		process_decl,        state.SPECIAL_SECTION:		process_special,        state.INLINE_NAME:		process_inline_name,        state.INLINE_TEXT:		process_inline_text,        state.PROTO:			process_proto,        state.DOCBLOCK:			process_docblock,        }     def parse_kdoc(self):        """        Open and process each line of a C source file.        The parsing is controlled via a state machine, and the line is passed        to a different process function depending on the state. The process        function may update the state as needed.         Besides parsing kernel-doc tags, it also parses export symbols.        """         prev = ""        prev_ln = None        export_table = set()         try:            with open(self.fname, "r", encoding="utf8",                      errors="backslashreplace") as fp:                for ln, line in enumerate(fp):                     line = line.expandtabs().strip("\n")                     # Group continuation lines on prototypes                    if self.state == state.PROTO:                        if line.endswith("\\"):                            prev += line.rstrip("\\")                            if not prev_ln:                                prev_ln = ln                            continue                         if prev:                            ln = prev_ln                            line = prev + line                            prev = ""                            prev_ln = None                     self.config.log.debug("%d %s: %s",                                          ln, state.name[self.state],                                          line)                     # This is an optimization over the original script.                    # There, when export_file was used for the same file,                    # it was read twice. Here, we use the already-existing                    # loop to parse exported symbols as well.                    #                    if (self.state != state.NORMAL) or \                       not self.process_export(export_table, line):                        # Hand this line to the appropriate state handler                        self.state_actions[self.state](self, ln, line)             self.emit_unused_warnings()         except OSError:            self.config.log.error(f"Error: Cannot open file {self.fname}")         return export_table, self.entries

Lines 1501–1784 of 1784. Previous lines