[libvirt] [PATCH v3 07/22] build-aux: rewrite header ifdef checker in Python

Daniel P. Berrangé berrange at redhat.com
Tue Sep 24 14:58:48 UTC 2019


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 at redhat.com>
---
 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




More information about the libvir-list mailing list