As part of an goal to eliminate Perl from libvirt build tools, rewrite the header-ifdef.pl tool in Python. This was a straight conversion, manually going line-by-line to change the syntax from Perl to Python. Thus the overall structure of the file and approach is the same. Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- Makefile.am | 2 +- build-aux/header-ifdef.pl | 182 ------------------------------ build-aux/header-ifdef.py | 231 ++++++++++++++++++++++++++++++++++++++ cfg.mk | 4 +- 4 files changed, 234 insertions(+), 185 deletions(-) delete mode 100644 build-aux/header-ifdef.pl create mode 100644 build-aux/header-ifdef.py diff --git a/Makefile.am b/Makefile.am index db77da890c..4ba729d3f7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,7 +44,7 @@ EXTRA_DIST = \ build-aux/augeas-gentest.py \ build-aux/check-spacing.py \ build-aux/gitlog-to-changelog \ - build-aux/header-ifdef.pl \ + build-aux/header-ifdef.py \ build-aux/minimize-po.py \ build-aux/mock-noinline.py \ build-aux/prohibit-duplicate-header.py \ diff --git a/build-aux/header-ifdef.pl b/build-aux/header-ifdef.pl deleted file mode 100644 index dba3dbcbdc..0000000000 --- a/build-aux/header-ifdef.pl +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/perl -# -# Validate that header files follow a standard layout: -# -# /* -# ...copyright header... -# */ -# <one blank line> -# #pragma once -# ....content.... -# -#--- -# -# For any file ending priv.h, before the #pragma once -# We will have a further section -# -# #ifndef SYMBOL_ALLOW -# # error .... -# #endif /* SYMBOL_ALLOW */ -# <one blank line> -# -#--- -# -# For public headers (files in include/), use the standard header guard instead of #pragma once: -# #ifndef SYMBOL -# # define SYMBOL -# ....content.... -# #endif /* SYMBOL */ - -use strict; -use warnings; - -my $STATE_COPYRIGHT_COMMENT = 0; -my $STATE_COPYRIGHT_BLANK = 1; -my $STATE_PRIV_START = 2; -my $STATE_PRIV_ERROR = 3; -my $STATE_PRIV_END = 4; -my $STATE_PRIV_BLANK = 5; -my $STATE_GUARD_START = 6; -my $STATE_GUARD_DEFINE = 7; -my $STATE_GUARD_END = 8; -my $STATE_EOF = 9; -my $STATE_PRAGMA = 10; - -my $file = " "; -my $ret = 0; -my $ifdef = ""; -my $ifdefpriv = ""; -my $publicheader = 0; - -my $state = $STATE_EOF; -my $mistake = 0; - -sub mistake { - my $msg = shift; - warn $msg; - $mistake = 1; - $ret = 1; -} - -while (<>) { - if (not $file eq $ARGV) { - if ($state == $STATE_COPYRIGHT_COMMENT) { - &mistake("$file: missing copyright comment"); - } elsif ($state == $STATE_COPYRIGHT_BLANK) { - &mistake("$file: missing blank line after copyright header"); - } elsif ($state == $STATE_PRIV_START) { - &mistake("$file: missing '#ifndef $ifdefpriv'"); - } elsif ($state == $STATE_PRIV_ERROR) { - &mistake("$file: missing '# error ...priv allow...'"); - } elsif ($state == $STATE_PRIV_END) { - &mistake("$file: missing '#endif /* $ifdefpriv */'"); - } elsif ($state == $STATE_PRIV_BLANK) { - &mistake("$file: missing blank line after priv header check"); - } elsif ($state == $STATE_GUARD_START) { - if ($publicheader) { - &mistake("$file: missing '#ifndef $ifdef'"); - } else { - &mistake("$file: missing '#pragma once' header guard"); - } - } elsif ($state == $STATE_GUARD_DEFINE) { - &mistake("$file: missing '# define $ifdef'"); - } elsif ($state == $STATE_GUARD_END) { - &mistake("$file: missing '#endif /* $ifdef */'"); - } - - $ifdef = uc $ARGV; - $ifdef =~ s,.*/,,; - $ifdef =~ s,[^A-Z0-9],_,g; - $ifdef =~ s,__+,_,g; - unless ($ifdef =~ /^LIBVIRT_/ && $ARGV !~ /libvirt_internal.h/) { - $ifdef = "LIBVIRT_" . $ifdef; - } - $ifdefpriv = $ifdef . "_ALLOW"; - - $file = $ARGV; - $state = $STATE_COPYRIGHT_COMMENT; - $mistake = 0; - $publicheader = ($ARGV =~ /include\//); - } - - if ($mistake || - $ARGV =~ /config-post\.h$/ || - $ARGV =~ /vbox_(CAPI|XPCOM)/) { - $state = $STATE_EOF; - next; - } - - if ($state == $STATE_COPYRIGHT_COMMENT) { - if (m,\*/,) { - $state = $STATE_COPYRIGHT_BLANK; - } - } elsif ($state == $STATE_COPYRIGHT_BLANK) { - if (! /^$/) { - &mistake("$file: missing blank line after copyright header"); - } - if ($ARGV =~ /priv\.h$/) { - $state = $STATE_PRIV_START; - } else { - $state = $STATE_GUARD_START; - } - } elsif ($state == $STATE_PRIV_START) { - if (/^$/) { - &mistake("$file: too many blank lines after copyright header"); - } elsif (/#ifndef $ifdefpriv$/) { - $state = $STATE_PRIV_ERROR; - } else { - &mistake("$file: missing '#ifndef $ifdefpriv'"); - } - } elsif ($state == $STATE_PRIV_ERROR) { - if (/# error ".*"$/) { - $state = $STATE_PRIV_END; - } else { - &mistake("$file: missing '# error ...priv allow...'"); - } - } elsif ($state == $STATE_PRIV_END) { - if (m,#endif /\* $ifdefpriv \*/,) { - $state = $STATE_PRIV_BLANK; - } else { - &mistake("$file: missing '#endif /* $ifdefpriv */'"); - } - } elsif ($state == $STATE_PRIV_BLANK) { - if (! /^$/) { - &mistake("$file: missing blank line after priv guard"); - } - $state = $STATE_GUARD_START; - } elsif ($state == $STATE_GUARD_START) { - if (/^$/) { - &mistake("$file: too many blank lines after copyright header"); - } - if ($publicheader) { - if (/#ifndef $ifdef$/) { - $state = $STATE_GUARD_DEFINE; - } else { - &mistake("$file: missing '#ifndef $ifdef'"); - } - } else { - if (/#pragma once/) { - $state = $STATE_PRAGMA; - } else { - &mistake("$file: missing '#pragma once' header guard"); - } - } - } elsif ($state == $STATE_GUARD_DEFINE) { - if (/# define $ifdef$/) { - $state = $STATE_GUARD_END; - } else { - &mistake("$file: missing '# define $ifdef'"); - } - } elsif ($state == $STATE_GUARD_END) { - if (m,#endif /\* $ifdef \*/$,) { - $state = $STATE_EOF; - } - } elsif ($state == $STATE_PRAGMA) { - next; - } elsif ($state == $STATE_EOF) { - die "$file: unexpected content after '#endif /* $ifdef */'"; - } else { - die "$file: unexpected state $state"; - } -} -exit $ret; diff --git a/build-aux/header-ifdef.py b/build-aux/header-ifdef.py new file mode 100644 index 0000000000..a192e01bc4 --- /dev/null +++ b/build-aux/header-ifdef.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018-2019 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# <http://www.gnu.org/licenses/>. +# +# Validate that header files follow a standard layout: +# +# /* +# ...copyright header... +# */ +# <one blank line> +# #pragma once +# ....content.... +# +# --- +# +# For any file ending priv.h, before the #pragma once +# We will have a further section +# +# #ifndef SYMBOL_ALLOW +# # error .... +# #endif /* SYMBOL_ALLOW */ +# <one blank line> +# +# --- +# +# For public headers (files in include/), use the standard +# header guard instead of #pragma once: +# #ifndef SYMBOL +# # define SYMBOL +# ....content.... +# #endif /* SYMBOL */ + +from __future__ import print_function + +import os.path +import re +import sys + +STATE_COPYRIGHT_COMMENT = 0 +STATE_COPYRIGHT_BLANK = 1 +STATE_PRIV_START = 2 +STATE_PRIV_ERROR = 3 +STATE_PRIV_END = 4 +STATE_PRIV_BLANK = 5 +STATE_GUARD_START = 6 +STATE_GUARD_DEFINE = 7 +STATE_GUARD_END = 8 +STATE_EOF = 9 +STATE_PRAGMA = 10 + + +def check_header(filename): + ifdef = "" + ifdefpriv = "" + + state = STATE_EOF + + ifdef = os.path.basename(filename).upper() + ifdef = re.sub(r"""[^A-Z0-9]""", "_", ifdef) + ifdef = re.sub(r"""__+""", "_", ifdef) + + if (not ifdef.startswith("LIBVIRT_") or + filename.find("libvirt_internal.h") != -1): + ifdef = "LIBVIRT_" + ifdef + + ifdefpriv = ifdef + "_ALLOW" + + state = STATE_COPYRIGHT_COMMENT + publicheader = False + if filename.find("include/") != -1: + publicheader = True + + with open(filename, "r") as fh: + for line in fh: + line = line.rstrip("\n") + if state == STATE_COPYRIGHT_COMMENT: + if line.find("*/") != -1: + state = STATE_COPYRIGHT_BLANK + elif state == STATE_COPYRIGHT_BLANK: + if line != "": + print("%s: missing blank line after copyright header" % + filename, file=sys.stderr) + return True + + if filename.endswith("priv.h"): + state = STATE_PRIV_START + else: + state = STATE_GUARD_START + elif state == STATE_PRIV_START: + if line == "": + print("%s: too many blank lines after copyright header" % + filename, file=sys.stderr) + return True + elif re.match(r"""#ifndef %s$""" % ifdefpriv, line): + state = STATE_PRIV_ERROR + else: + print("%s: missing '#ifndef %s'" % (filename, ifdefpriv), + file=sys.stderr) + return True + elif state == STATE_PRIV_ERROR: + if re.match(r"""# error ".*"$""", line): + state = STATE_PRIV_END + else: + print("%s: missing '# error ...priv allow...'" % + filename, file=sys.stderr) + return True + elif state == STATE_PRIV_END: + if re.match(r"""#endif /\* %s \*/""" % ifdefpriv, line): + state = STATE_PRIV_BLANK + else: + print("%s: missing '#endif /* %s */'" % + (filename, ifdefpriv), file=sys.stderr) + return True + elif state == STATE_PRIV_BLANK: + if line != "": + print("%s: missing blank line after priv guard" % + filename, file=sys.stderr) + return True + state = STATE_GUARD_START + elif state == STATE_GUARD_START: + if line == "": + print("%s: too many blank lines after copyright header" % + filename, file=sys.stderr) + return True + if publicheader: + if re.match(r"""#ifndef %s$""" % ifdef, line): + state = STATE_GUARD_DEFINE + else: + print("%s: missing '#ifndef %s'" % + (filename, ifdef), file=sys.stderr) + return True + else: + if re.match(r"""#pragma once""", line): + state = STATE_PRAGMA + else: + print("%s: missing '#pragma once' header guard" % + filename, file=sys.stderr) + return True + elif state == STATE_GUARD_DEFINE: + if re.match(r"""# define %s$""" % ifdef, line): + state = STATE_GUARD_END + else: + print("%s: missing '# define %s'" % + (filename, ifdef), file=sys.stderr) + return True + elif state == STATE_GUARD_END: + if re.match(r"""#endif /\* %s \*/$""" % ifdef, line): + state = STATE_EOF + elif state == STATE_PRAGMA: + next + elif state == STATE_EOF: + print("%s: unexpected content after '#endif /* %s */'" % + (filename, ifdef), file=sys.stderr) + return True + else: + print("%s: unexpected state $state" % + filename, file=sys.stderr) + return True + + if state == STATE_COPYRIGHT_COMMENT: + print("%s: missing copyright comment" % + filename, file=sys.stderr) + return True + elif state == STATE_COPYRIGHT_BLANK: + print("%s: missing blank line after copyright header" % + filename, file=sys.stderr) + return True + elif state == STATE_PRIV_START: + print("%s: missing '#ifndef %s'" % + (filename, ifdefpriv), file=sys.stderr) + return True + elif state == STATE_PRIV_ERROR: + print("%s: missing '# error ...priv allow...'" % + filename, file=sys.stderr) + return True + elif state == STATE_PRIV_END: + print("%s: missing '#endif /* %s */'" % + (filename, ifdefpriv), file=sys.stderr) + return True + elif state == STATE_PRIV_BLANK: + print("%s: missing blank line after priv header check" % + filename, file=sys.stderr) + return True + elif state == STATE_GUARD_START: + if publicheader: + print("%s: missing '#ifndef %s'" % + (filename, ifdef), file=sys.stderr) + return True + else: + print("%s: missing '#pragma once' header guard" % + filename, file=sys.stderr) + return True + elif state == STATE_GUARD_DEFINE: + print("%s: missing '# define %s'" % + (filename, ifdef), file=sys.stderr) + return True + elif state == STATE_GUARD_END: + print("%s: missing '#endif /* %s */'" % + (filename, ifdef), file=sys.stderr) + return True + + return False + + +ret = 0 + +for filename in sys.argv[1:]: + if filename.find("config-post.h") != -1: + continue + if filename.find("vbox_CAPI") != -1: + continue + if filename.find("vbox_XPCOM") != -1: + continue + if check_header(filename): + ret = 1 + +sys.exit(ret) diff --git a/cfg.mk b/cfg.mk index b73d3ae1bf..f0aed0365a 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1165,8 +1165,8 @@ mock-noinline: $(PYTHON) $(top_srcdir)/build-aux/mock-noinline.py header-ifdef: - $(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[h]$$' | xargs \ - $(PERL) $(top_srcdir)/build-aux/header-ifdef.pl + $(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[h]$$' | $(RUNUTF8) xargs \ + $(PYTHON) $(top_srcdir)/build-aux/header-ifdef.py test-wrap-argv: $(AM_V_GEN)$(VC_LIST) | $(GREP) -E '\.(ldargs|args)' | xargs \ -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list