Blame scripts/check-obsolete-constructs.py

Packit Service 27050d
#! /usr/bin/python3
Packit Service 27050d
# Copyright (C) 2019 Free Software Foundation, Inc.
Packit Service 27050d
# This file is part of the GNU C Library.
Packit Service 27050d
#
Packit Service 27050d
# The GNU C Library is free software; you can redistribute it and/or
Packit Service 27050d
# modify it under the terms of the GNU Lesser General Public
Packit Service 27050d
# License as published by the Free Software Foundation; either
Packit Service 27050d
# version 2.1 of the License, or (at your option) any later version.
Packit Service 27050d
#
Packit Service 27050d
# The GNU C Library is distributed in the hope that it will be useful,
Packit Service 27050d
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 27050d
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 27050d
# Lesser General Public License for more details.
Packit Service 27050d
#
Packit Service 27050d
# You should have received a copy of the GNU Lesser General Public
Packit Service 27050d
# License along with the GNU C Library; if not, see
Packit Service 27050d
# <http://www.gnu.org/licenses/>.
Packit Service 27050d
Packit Service 27050d
"""Verifies that installed headers do not use any obsolete constructs:
Packit Service 27050d
 * legacy BSD typedefs superseded by <stdint.h>:
Packit Service 27050d
   ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t
Packit Service 27050d
   (sys/types.h is allowed to _define_ these types, but not to use them
Packit Service 27050d
    to define anything else).
Packit Service 27050d
"""
Packit Service 27050d
Packit Service 27050d
import argparse
Packit Service 27050d
import collections
Packit Service 27050d
import re
Packit Service 27050d
import sys
Packit Service 27050d
Packit Service 27050d
# Simplified lexical analyzer for C preprocessing tokens.
Packit Service 27050d
# Does not implement trigraphs.
Packit Service 27050d
# Does not implement backslash-newline in the middle of any lexical
Packit Service 27050d
#   item other than a string literal.
Packit Service 27050d
# Does not implement universal-character-names in identifiers.
Packit Service 27050d
# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
Packit Service 27050d
# Accepts non-ASCII characters only within comments and strings.
Packit Service 27050d
Packit Service 27050d
# Caution: The order of the outermost alternation matters.
Packit Service 27050d
# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
Packit Service 27050d
# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
Packit Service 27050d
# be last.
Packit Service 27050d
# Caution: There should be no capturing groups other than the named
Packit Service 27050d
# captures in the outermost alternation.
Packit Service 27050d
Packit Service 27050d
# For reference, these are all of the C punctuators as of C11:
Packit Service 27050d
#   [ ] ( ) { } , ; ? ~
Packit Service 27050d
#   ! != * *= / /= ^ ^= = ==
Packit Service 27050d
#   # ##
Packit Service 27050d
#   % %= %> %: %:%:
Packit Service 27050d
#   & &= &&
Packit Service 27050d
#   | |= ||
Packit Service 27050d
#   + += ++
Packit Service 27050d
#   - -= -- ->
Packit Service 27050d
#   . ...
Packit Service 27050d
#   : :>
Packit Service 27050d
#   < <% <: << <<= <=
Packit Service 27050d
#   > >= >> >>=
Packit Service 27050d
Packit Service 27050d
# The BAD_* tokens are not part of the official definition of pp-tokens;
Packit Service 27050d
# they match unclosed strings, character constants, and block comments,
Packit Service 27050d
# so that the regex engine doesn't have to backtrack all the way to the
Packit Service 27050d
# beginning of a broken construct and then emit dozens of junk tokens.
Packit Service 27050d
Packit Service 27050d
PP_TOKEN_RE_ = re.compile(r"""
Packit Service 27050d
    (?P<STRING>        \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
Packit Service 27050d
   |(?P<BAD_STRING>    \"(?:[^\"\\\r\n]|\\[ -~])*)
Packit Service 27050d
   |(?P<CHARCONST>     \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
Packit Service 27050d
   |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
Packit Service 27050d
   |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
Packit Service 27050d
   |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
Packit Service 27050d
   |(?P<LINE_COMMENT>  //[^\r\n]*)
Packit Service 27050d
   |(?P<IDENT>         [_a-zA-Z][_a-zA-Z0-9]*)
Packit Service 27050d
   |(?P<PP_NUMBER>     \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
Packit Service 27050d
   |(?P<PUNCTUATOR>
Packit Service 27050d
       [,;?~(){}\[\]]
Packit Service 27050d
     | [!*/^=]=?
Packit Service 27050d
     | \#\#?
Packit Service 27050d
     | %(?:[=>]|:(?:%:)?)?
Packit Service 27050d
     | &[=&]?
Packit Service 27050d
     |\|[=|]?
Packit Service 27050d
     |\+[=+]?
Packit Service 27050d
     | -[=->]?
Packit Service 27050d
     |\.(?:\.\.)?
Packit Service 27050d
     | :>?
Packit Service 27050d
     | <(?:[%:]|<(?:=|<=?)?)?
Packit Service 27050d
     | >(?:=|>=?)?)
Packit Service 27050d
   |(?P<ESCNL>         \\(?:\r|\n|\r\n))
Packit Service 27050d
   |(?P<WHITESPACE>    [ \t\n\r\v\f]+)
Packit Service 27050d
   |(?P<OTHER>         .)
Packit Service 27050d
""", re.DOTALL | re.VERBOSE)
Packit Service 27050d
Packit Service 27050d
HEADER_NAME_RE_ = re.compile(r"""
Packit Service 27050d
    < [^>\r\n]+ >
Packit Service 27050d
  | " [^"\r\n]+ "
Packit Service 27050d
""", re.DOTALL | re.VERBOSE)
Packit Service 27050d
Packit Service 27050d
ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
Packit Service 27050d
Packit Service 27050d
# based on the sample code in the Python re documentation
Packit Service 27050d
Token_ = collections.namedtuple("Token", (
Packit Service 27050d
    "kind", "text", "line", "column", "context"))
Packit Service 27050d
Token_.__doc__ = """
Packit Service 27050d
   One C preprocessing token, comment, or chunk of whitespace.
Packit Service 27050d
   'kind' identifies the token type, which will be one of:
Packit Service 27050d
       STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
Packit Service 27050d
       PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
Packit Service 27050d
       or OTHER.  The BAD_* alternatives in PP_TOKEN_RE_ are
Packit Service 27050d
       handled within tokenize_c, below.
Packit Service 27050d
Packit Service 27050d
   'text' is the sequence of source characters making up the token;
Packit Service 27050d
       no decoding whatsoever is performed.
Packit Service 27050d
Packit Service 27050d
   'line' and 'column' give the position of the first character of the
Packit Service 27050d
      token within the source file.  They are both 1-based.
Packit Service 27050d
Packit Service 27050d
   'context' indicates whether or not this token occurred within a
Packit Service 27050d
      preprocessing directive; it will be None for running text,
Packit Service 27050d
      '<null>' for the leading '#' of a directive line (because '#'
Packit Service 27050d
      all by itself on a line is a "null directive"), or the name of
Packit Service 27050d
      the directive for tokens within a directive line, starting with
Packit Service 27050d
      the IDENT for the name itself.
Packit Service 27050d
"""
Packit Service 27050d
Packit Service 27050d
def tokenize_c(file_contents, reporter):
Packit Service 27050d
    """Yield a series of Token objects, one for each preprocessing
Packit Service 27050d
       token, comment, or chunk of whitespace within FILE_CONTENTS.
Packit Service 27050d
       The REPORTER object is expected to have one method,
Packit Service 27050d
       reporter.error(token, message), which will be called to
Packit Service 27050d
       indicate a lexical error at the position of TOKEN.
Packit Service 27050d
       If MESSAGE contains the four-character sequence '{!r}', that
Packit Service 27050d
       is expected to be replaced by repr(token.text).
Packit Service 27050d
    """
Packit Service 27050d
Packit Service 27050d
    Token = Token_
Packit Service 27050d
    PP_TOKEN_RE = PP_TOKEN_RE_
Packit Service 27050d
    ENDLINE_RE = ENDLINE_RE_
Packit Service 27050d
    HEADER_NAME_RE = HEADER_NAME_RE_
Packit Service 27050d
Packit Service 27050d
    line_num = 1
Packit Service 27050d
    line_start = 0
Packit Service 27050d
    pos = 0
Packit Service 27050d
    limit = len(file_contents)
Packit Service 27050d
    directive = None
Packit Service 27050d
    at_bol = True
Packit Service 27050d
    while pos < limit:
Packit Service 27050d
        if directive == "include":
Packit Service 27050d
            mo = HEADER_NAME_RE.match(file_contents, pos)
Packit Service 27050d
            if mo:
Packit Service 27050d
                kind = "HEADER_NAME"
Packit Service 27050d
                directive = "after_include"
Packit Service 27050d
            else:
Packit Service 27050d
                mo = PP_TOKEN_RE.match(file_contents, pos)
Packit Service 27050d
                kind = mo.lastgroup
Packit Service 27050d
                if kind != "WHITESPACE":
Packit Service 27050d
                    directive = "after_include"
Packit Service 27050d
        else:
Packit Service 27050d
            mo = PP_TOKEN_RE.match(file_contents, pos)
Packit Service 27050d
            kind = mo.lastgroup
Packit Service 27050d
Packit Service 27050d
        text = mo.group()
Packit Service 27050d
        line = line_num
Packit Service 27050d
        column = mo.start() - line_start
Packit Service 27050d
        adj_line_start = 0
Packit Service 27050d
        # only these kinds can contain a newline
Packit Service 27050d
        if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
Packit Service 27050d
                    "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
Packit Service 27050d
            for tmo in ENDLINE_RE.finditer(text):
Packit Service 27050d
                line_num += 1
Packit Service 27050d
                adj_line_start = tmo.end()
Packit Service 27050d
            if adj_line_start:
Packit Service 27050d
                line_start = mo.start() + adj_line_start
Packit Service 27050d
Packit Service 27050d
        # Track whether or not we are scanning a preprocessing directive.
Packit Service 27050d
        if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
Packit Service 27050d
            at_bol = True
Packit Service 27050d
            directive = None
Packit Service 27050d
        else:
Packit Service 27050d
            if kind == "PUNCTUATOR" and text == "#" and at_bol:
Packit Service 27050d
                directive = "<null>"
Packit Service 27050d
            elif kind == "IDENT" and directive == "<null>":
Packit Service 27050d
                directive = text
Packit Service 27050d
            at_bol = False
Packit Service 27050d
Packit Service 27050d
        # Report ill-formed tokens and rewrite them as their well-formed
Packit Service 27050d
        # equivalents, so downstream processing doesn't have to know about them.
Packit Service 27050d
        # (Rewriting instead of discarding provides better error recovery.)
Packit Service 27050d
        if kind == "BAD_BLOCK_COM":
Packit Service 27050d
            reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
Packit Service 27050d
                           "unclosed block comment")
Packit Service 27050d
            text += "*/"
Packit Service 27050d
            kind = "BLOCK_COMMENT"
Packit Service 27050d
        elif kind == "BAD_STRING":
Packit Service 27050d
            reporter.error(Token("BAD_STRING", "", line, column+1, ""),
Packit Service 27050d
                           "unclosed string")
Packit Service 27050d
            text += "\""
Packit Service 27050d
            kind = "STRING"
Packit Service 27050d
        elif kind == "BAD_CHARCONST":
Packit Service 27050d
            reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
Packit Service 27050d
                           "unclosed char constant")
Packit Service 27050d
            text += "'"
Packit Service 27050d
            kind = "CHARCONST"
Packit Service 27050d
Packit Service 27050d
        tok = Token(kind, text, line, column+1,
Packit Service 27050d
                    "include" if directive == "after_include" else directive)
Packit Service 27050d
        # Do not complain about OTHER tokens inside macro definitions.
Packit Service 27050d
        # $ and @ appear in macros defined by headers intended to be
Packit Service 27050d
        # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
Packit Service 27050d
        if kind == "OTHER" and directive != "define":
Packit Service 27050d
            self.error(tok, "stray {!r} in program")
Packit Service 27050d
Packit Service 27050d
        yield tok
Packit Service 27050d
        pos = mo.end()
Packit Service 27050d
Packit Service 27050d
#
Packit Service 27050d
# Base and generic classes for individual checks.
Packit Service 27050d
#
Packit Service 27050d
Packit Service 27050d
class ConstructChecker:
Packit Service 27050d
    """Scan a stream of C preprocessing tokens and possibly report
Packit Service 27050d
       problems with them.  The REPORTER object passed to __init__ has
Packit Service 27050d
       one method, reporter.error(token, message), which should be
Packit Service 27050d
       called to indicate a problem detected at the position of TOKEN.
Packit Service 27050d
       If MESSAGE contains the four-character sequence '{!r}' then that
Packit Service 27050d
       will be replaced with a textual representation of TOKEN.
Packit Service 27050d
    """
Packit Service 27050d
    def __init__(self, reporter):
Packit Service 27050d
        self.reporter = reporter
Packit Service 27050d
Packit Service 27050d
    def examine(self, tok):
Packit Service 27050d
        """Called once for each token in a header file.
Packit Service 27050d
           Call self.reporter.error if a problem is detected.
Packit Service 27050d
        """
Packit Service 27050d
        raise NotImplementedError
Packit Service 27050d
Packit Service 27050d
    def eof(self):
Packit Service 27050d
        """Called once at the end of the stream.  Subclasses need only
Packit Service 27050d
           override this if it might have something to do."""
Packit Service 27050d
        pass
Packit Service 27050d
Packit Service 27050d
class NoCheck(ConstructChecker):
Packit Service 27050d
    """Generic checker class which doesn't do anything.  Substitute this
Packit Service 27050d
       class for a real checker when a particular check should be skipped
Packit Service 27050d
       for some file."""
Packit Service 27050d
Packit Service 27050d
    def examine(self, tok):
Packit Service 27050d
        pass
Packit Service 27050d
Packit Service 27050d
#
Packit Service 27050d
# Check for obsolete type names.
Packit Service 27050d
#
Packit Service 27050d
Packit Service 27050d
# The obsolete type names we're looking for:
Packit Service 27050d
OBSOLETE_TYPE_RE_ = re.compile(r"""\A
Packit Service 27050d
  (__)?
Packit Service 27050d
  (   quad_t
Packit Service 27050d
    | u(?: short | int | long
Packit Service 27050d
         | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t )))
Packit Service 27050d
\Z""", re.VERBOSE)
Packit Service 27050d
Packit Service 27050d
class ObsoleteNotAllowed(ConstructChecker):
Packit Service 27050d
    """Don't allow any use of the obsolete typedefs."""
Packit Service 27050d
    def examine(self, tok):
Packit Service 27050d
        if OBSOLETE_TYPE_RE_.match(tok.text):
Packit Service 27050d
            self.reporter.error(tok, "use of {!r}")
Packit Service 27050d
Packit Service 27050d
class ObsoletePrivateDefinitionsAllowed(ConstructChecker):
Packit Service 27050d
    """Allow definitions of the private versions of the
Packit Service 27050d
       obsolete typedefs; that is, 'typedef [anything] __obsolete;'
Packit Service 27050d
    """
Packit Service 27050d
    def __init__(self, reporter):
Packit Service 27050d
        super().__init__(reporter)
Packit Service 27050d
        self.in_typedef = False
Packit Service 27050d
        self.prev_token = None
Packit Service 27050d
Packit Service 27050d
    def examine(self, tok):
Packit Service 27050d
        # bits/types.h hides 'typedef' in a macro sometimes.
Packit Service 27050d
        if (tok.kind == "IDENT"
Packit Service 27050d
            and tok.text in ("typedef", "__STD_TYPE")
Packit Service 27050d
            and tok.context is None):
Packit Service 27050d
            self.in_typedef = True
Packit Service 27050d
        elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef:
Packit Service 27050d
            self.in_typedef = False
Packit Service 27050d
            if self.prev_token.kind == "IDENT":
Packit Service 27050d
                m = OBSOLETE_TYPE_RE_.match(self.prev_token.text)
Packit Service 27050d
                if m and m.group(1) != "__":
Packit Service 27050d
                    self.reporter.error(self.prev_token, "use of {!r}")
Packit Service 27050d
            self.prev_token = None
Packit Service 27050d
        else:
Packit Service 27050d
            self._check_prev()
Packit Service 27050d
Packit Service 27050d
        self.prev_token = tok
Packit Service 27050d
Packit Service 27050d
    def eof(self):
Packit Service 27050d
        self._check_prev()
Packit Service 27050d
Packit Service 27050d
    def _check_prev(self):
Packit Service 27050d
        if (self.prev_token is not None
Packit Service 27050d
            and self.prev_token.kind == "IDENT"
Packit Service 27050d
            and OBSOLETE_TYPE_RE_.match(self.prev_token.text)):
Packit Service 27050d
            self.reporter.error(self.prev_token, "use of {!r}")
Packit Service 27050d
Packit Service 27050d
class ObsoletePublicDefinitionsAllowed(ConstructChecker):
Packit Service 27050d
    """Allow definitions of the public versions of the obsolete
Packit Service 27050d
       typedefs.  Only specific forms of definition are allowed:
Packit Service 27050d
Packit Service 27050d
           typedef __obsolete obsolete;  // identifiers must agree
Packit Service 27050d
           typedef __uintN_t u_intN_t;   // N must agree
Packit Service 27050d
           typedef unsigned long int ulong;
Packit Service 27050d
           typedef unsigned short int ushort;
Packit Service 27050d
           typedef unsigned int uint;
Packit Service 27050d
    """
Packit Service 27050d
    def __init__(self, reporter):
Packit Service 27050d
        super().__init__(reporter)
Packit Service 27050d
        self.typedef_tokens = []
Packit Service 27050d
Packit Service 27050d
    def examine(self, tok):
Packit Service 27050d
        if tok.kind in ("WHITESPACE", "BLOCK_COMMENT",
Packit Service 27050d
                        "LINE_COMMENT", "NL", "ESCNL"):
Packit Service 27050d
            pass
Packit Service 27050d
Packit Service 27050d
        elif (tok.kind == "IDENT" and tok.text == "typedef"
Packit Service 27050d
              and tok.context is None):
Packit Service 27050d
            if self.typedef_tokens:
Packit Service 27050d
                self.reporter.error(tok, "typedef inside typedef")
Packit Service 27050d
                self._reset()
Packit Service 27050d
            self.typedef_tokens.append(tok)
Packit Service 27050d
Packit Service 27050d
        elif tok.kind == "PUNCTUATOR" and tok.text == ";":
Packit Service 27050d
            self._finish()
Packit Service 27050d
Packit Service 27050d
        elif self.typedef_tokens:
Packit Service 27050d
            self.typedef_tokens.append(tok)
Packit Service 27050d
Packit Service 27050d
    def eof(self):
Packit Service 27050d
        self._reset()
Packit Service 27050d
Packit Service 27050d
    def _reset(self):
Packit Service 27050d
        while self.typedef_tokens:
Packit Service 27050d
            tok = self.typedef_tokens.pop(0)
Packit Service 27050d
            if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text):
Packit Service 27050d
                self.reporter.error(tok, "use of {!r}")
Packit Service 27050d
Packit Service 27050d
    def _finish(self):
Packit Service 27050d
        if not self.typedef_tokens: return
Packit Service 27050d
        if self.typedef_tokens[-1].kind == "IDENT":
Packit Service 27050d
            m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text)
Packit Service 27050d
            if m:
Packit Service 27050d
                if self._permissible_public_definition(m):
Packit Service 27050d
                    self.typedef_tokens.clear()
Packit Service 27050d
        self._reset()
Packit Service 27050d
Packit Service 27050d
    def _permissible_public_definition(self, m):
Packit Service 27050d
        if m.group(1) == "__": return False
Packit Service 27050d
        name = m.group(2)
Packit Service 27050d
        toks = self.typedef_tokens
Packit Service 27050d
        ntok = len(toks)
Packit Service 27050d
        if ntok == 3 and toks[1].kind == "IDENT":
Packit Service 27050d
            defn = toks[1].text
Packit Service 27050d
            n = OBSOLETE_TYPE_RE_.match(defn)
Packit Service 27050d
            if n and n.group(1) == "__" and n.group(2) == name:
Packit Service 27050d
                return True
Packit Service 27050d
Packit Service 27050d
            if (name[:5] == "u_int" and name[-2:] == "_t"
Packit Service 27050d
                and defn[:6] == "__uint" and defn[-2:] == "_t"
Packit Service 27050d
                and name[5:-2] == defn[6:-2]):
Packit Service 27050d
                return True
Packit Service 27050d
Packit Service 27050d
            return False
Packit Service 27050d
Packit Service 27050d
        if (name == "ulong" and ntok == 5
Packit Service 27050d
            and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
Packit Service 27050d
            and toks[2].kind == "IDENT" and toks[2].text == "long"
Packit Service 27050d
            and toks[3].kind == "IDENT" and toks[3].text == "int"):
Packit Service 27050d
            return True
Packit Service 27050d
Packit Service 27050d
        if (name == "ushort" and ntok == 5
Packit Service 27050d
            and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
Packit Service 27050d
            and toks[2].kind == "IDENT" and toks[2].text == "short"
Packit Service 27050d
            and toks[3].kind == "IDENT" and toks[3].text == "int"):
Packit Service 27050d
            return True
Packit Service 27050d
Packit Service 27050d
        if (name == "uint" and ntok == 4
Packit Service 27050d
            and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
Packit Service 27050d
            and toks[2].kind == "IDENT" and toks[2].text == "int"):
Packit Service 27050d
            return True
Packit Service 27050d
Packit Service 27050d
        return False
Packit Service 27050d
Packit Service 27050d
def ObsoleteTypedefChecker(reporter, fname):
Packit Service 27050d
    """Factory: produce an instance of the appropriate
Packit Service 27050d
       obsolete-typedef checker for FNAME."""
Packit Service 27050d
Packit Service 27050d
    # The obsolete rpc/ and rpcsvc/ headers are allowed to use the
Packit Service 27050d
    # obsolete types, because it would be more trouble than it's
Packit Service 27050d
    # worth to remove them from headers that we intend to stop
Packit Service 27050d
    # installing eventually anyway.
Packit Service 27050d
    if (fname.startswith("rpc/")
Packit Service 27050d
        or fname.startswith("rpcsvc/")
Packit Service 27050d
        or "/rpc/" in fname
Packit Service 27050d
        or "/rpcsvc/" in fname):
Packit Service 27050d
        return NoCheck(reporter)
Packit Service 27050d
Packit Service 27050d
    # bits/types.h is allowed to define the __-versions of the
Packit Service 27050d
    # obsolete types.
Packit Service 27050d
    if (fname == "bits/types.h"
Packit Service 27050d
        or fname.endswith("/bits/types.h")):
Packit Service 27050d
        return ObsoletePrivateDefinitionsAllowed(reporter)
Packit Service 27050d
Packit Service 27050d
    # sys/types.h is allowed to use the __-versions of the
Packit Service 27050d
    # obsolete types, but only to define the unprefixed versions.
Packit Service 27050d
    if (fname == "sys/types.h"
Packit Service 27050d
        or fname.endswith("/sys/types.h")):
Packit Service 27050d
        return ObsoletePublicDefinitionsAllowed(reporter)
Packit Service 27050d
Packit Service 27050d
    return ObsoleteNotAllowed(reporter)
Packit Service 27050d
Packit Service 27050d
#
Packit Service 27050d
# Master control
Packit Service 27050d
#
Packit Service 27050d
Packit Service 27050d
class HeaderChecker:
Packit Service 27050d
    """Perform all of the checks on each header.  This is also the
Packit Service 27050d
       "reporter" object expected by tokenize_c and ConstructChecker.
Packit Service 27050d
    """
Packit Service 27050d
    def __init__(self):
Packit Service 27050d
        self.fname = None
Packit Service 27050d
        self.status = 0
Packit Service 27050d
Packit Service 27050d
    def error(self, tok, message):
Packit Service 27050d
        self.status = 1
Packit Service 27050d
        if '{!r}' in message:
Packit Service 27050d
            message = message.format(tok.text)
Packit Service 27050d
        sys.stderr.write("{}:{}:{}: error: {}\n".format(
Packit Service 27050d
            self.fname, tok.line, tok.column, message))
Packit Service 27050d
Packit Service 27050d
    def check(self, fname):
Packit Service 27050d
        self.fname = fname
Packit Service 27050d
        try:
Packit Service 27050d
            with open(fname, "rt") as fp:
Packit Service 27050d
                contents = fp.read()
Packit Service 27050d
        except OSError as e:
Packit Service 27050d
            sys.stderr.write("{}: {}\n".format(fname, e.strerror))
Packit Service 27050d
            self.status = 1
Packit Service 27050d
            return
Packit Service 27050d
Packit Service 27050d
        typedef_checker = ObsoleteTypedefChecker(self, self.fname)
Packit Service 27050d
Packit Service 27050d
        for tok in tokenize_c(contents, self):
Packit Service 27050d
            typedef_checker.examine(tok)
Packit Service 27050d
Packit Service 27050d
def main():
Packit Service 27050d
    ap = argparse.ArgumentParser(description=__doc__)
Packit Service 27050d
    ap.add_argument("headers", metavar="header", nargs="+",
Packit Service 27050d
                    help="one or more headers to scan for obsolete constructs")
Packit Service 27050d
    args = ap.parse_args()
Packit Service 27050d
Packit Service 27050d
    checker = HeaderChecker()
Packit Service 27050d
    for fname in args.headers:
Packit Service 27050d
        # Headers whose installed name begins with "finclude/" contain
Packit Service 27050d
        # Fortran, not C, and this program should completely ignore them.
Packit Service 27050d
        if not (fname.startswith("finclude/") or "/finclude/" in fname):
Packit Service 27050d
            checker.check(fname)
Packit Service 27050d
    sys.exit(checker.status)
Packit Service 27050d
Packit Service 27050d
main()