Blame scripts/check-obsolete-constructs.py

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