From: Alexey Dobriyan <adobriyan@gmail.com>
To: torvalds@linux-foundation.org
Cc: linux-kernel@vger.kernel.org, akpm@linux-foundation.org
Subject: [PATCH 11/11] pragma once: conversion script (in Python 2)
Date: Sun, 28 Feb 2021 20:05:49 +0300 [thread overview]
Message-ID: <YDvNbbHd2cKXlLme@localhost.localdomain> (raw)
In-Reply-To: <YDvLYzsGu+l1pQ2y@localhost.localdomain>
From 2bffcdfec69a8d28e9cb2c535724fbba8e12b820 Mon Sep 17 00:00:00 2001
From: Alexey Dobriyan <adobriyan@gmail.com>
Date: Tue, 9 Feb 2021 14:47:34 +0300
Subject: [PATCH 11/11] pragma once: conversion script (in Python 2)
Script accepts list of files to be converted from the command line,
strips include guard if any and inserts "#pragma once" directive in
the beginning.
The following patterns are recognised:
#ifndef FOO_H #ifndef FOO_H
#define FOO_H #ifndef FOO_H 1
#endif
#endif // comment
#endif /* one line comment */
This is how almost all include guards look like.
Scripts doesn't pretend to be a compiler. For example, comments inside
preprocessor directive aren't recognised because people don't write code
like this:
# /*
* legal C
*/ def\
ine FOO /*
* no, we don't care
*/
Trailing multiline comments aren't recognised as well.
Script can cut through SPDX comments:
/* SPDX-License-Identifier: xxx
* <=== pragma once will be inserted here
* Copyright ...
*/
In other words, the script is simple but not too simple.
It cowardly exits and doesn't do anything as a safety measure in case of
an existing pragma once directive, missing/broken include guard or a bug.
Running it second time shouldn't do anything.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---
scripts/pragma-once.py | 159 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 159 insertions(+)
create mode 100755 scripts/pragma-once.py
diff --git a/scripts/pragma-once.py b/scripts/pragma-once.py
new file mode 100755
index 000000000000..7c8a274aad28
--- /dev/null
+++ b/scripts/pragma-once.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python2
+# Copyright (c) 2021 Alexey Dobriyan <adobriyan@gmail.com>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# Change include guard to "#pragma once" directive in place.
+import os
+import re
+import sys
+
+def read_file(filename):
+ with open(filename) as f:
+ return f.read()
+
+def write_file(filename, buf):
+ tmp = '%s.pragma-once' % filename
+ with open(tmp, 'w') as f:
+ f.write(buf)
+ os.rename(tmp, filename)
+
+def ws(c):
+ return c == ' ' or c == '\t' or c == '\n'
+
+re_ifndef = re.compile('#[ \t]*ifndef[ \t]+([A-Za-z_][A-Za-z0-9_]*)\n')
+re_define = re.compile('#[ \t]*define[ \t]+([A-Za-z_][A-Za-z0-9_]*)([ \t]+1)?\n')
+re_endif1 = re.compile('#[ \t]*endif[ \t]*//')
+re_endif2 = re.compile('#[ \t]*endif[ \t]*/\*')
+
+def pragma_once(c):
+ i = 0
+
+ # skip leading whitespace and comments
+ while i < len(c):
+ if ws(c[i]):
+ i += 1
+ elif c[i] == '/' and c[i + 1] == '*':
+ i = c.index('*/', i + 2) + 2
+ elif c[i] == '/' and c[i + 1] == '/':
+ i = c.index('\n', i + 2) + 1
+ else:
+ break;
+
+ # find #ifndef
+ ifndef_start = i
+ match = re_ifndef.match(c, i)
+ guard = match.group(1)
+ i = match.end()
+
+ # find #define
+ match = re_define.match(c, i)
+ if match.group(1) != guard:
+ raise
+ i = match.end()
+
+ while ws(c[i]):
+ i += 1
+
+ define_end = i
+
+ # trim whitespace before #ifndef
+ i = ifndef_start
+ while i > 0 and ws(c[i - 1]):
+ i -= 1
+ if c[i] == '\n':
+ i += 1
+ ifndef_start = i
+
+ #print repr(c[ifndef_start:define_end])
+
+ # find #endif
+ i = c.rindex('\n#endif', i) + 1
+ endif_start = i
+
+ match = None
+ if match is None:
+ match = re_endif1.match(c, i)
+ if match:
+ try:
+ i = c.index('\n', match.end()) + 1
+ except ValueError:
+ i = len(c)
+
+ if match is None:
+ match = re_endif2.match(c, i)
+ if match:
+ try:
+ i = c.index('*/', match.end()) + 2
+ except ValueError:
+ i = len(c)
+
+ if match is None:
+ i = endif_start + len('#endif')
+
+ while i < len(c) and ws(c[i]):
+ i += 1
+ if i != len(c):
+ raise
+
+ endif_end = i
+
+ # trim whitespace before #endif
+ i = endif_start
+ while i > 0 and ws(c[i - 1]):
+ i -= 1
+ if c[i] == '\n':
+ i += 1
+ endif_start = i
+
+ #print repr(c[endif_start:endif_end])
+
+ if define_end > endif_start:
+ raise
+
+ spdx_end = None
+ pragma_once = '#pragma once\n'
+ cut_comment = False
+ if c.startswith('/* SPDX'):
+ spdx_end = c.index('\n') + 1
+ if not (c[spdx_end - 3] == '*' and c[spdx_end - 2] == '/'):
+ cut_comment = True
+ elif c.startswith('// SPDX') or c.startswith('//SPDX'):
+ spdx_end = c.index('\n') + 1
+
+ if spdx_end is None:
+ l = [pragma_once, c[0:ifndef_start]]
+ elif cut_comment:
+ l = [c[0:spdx_end - 1], ' */\n', pragma_once, '/*\n', c[spdx_end:ifndef_start]]
+ else:
+ l = [c[0:spdx_end], pragma_once, c[spdx_end:ifndef_start]]
+
+ l.append(c[define_end:endif_start])
+ l.append(c[endif_end:])
+ return ''.join(l)
+
+def main():
+ for filename in sys.argv[1:]:
+ s = ''
+ try:
+ buf = read_file(filename)
+ if buf.find('#pragma once') == -1:
+ write_file(filename, pragma_once(buf))
+ else:
+ s = 'skip '
+ except:
+ pass
+ print '#pragma once: %s%s' % (s, filename)
+
+if __name__ == '__main__':
+ main()
--
2.29.2
next prev parent reply other threads:[~2021-02-28 17:06 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-28 16:57 [PATCH 00/11] pragma once: treewide conversion Alexey Dobriyan
2021-02-28 16:58 ` [PATCH 01/11] pragma once: delete include/linux/atm_suni.h Alexey Dobriyan
2021-02-28 19:05 ` Jakub Kicinski
2021-02-28 16:59 ` [PATCH 02/11] pragma once: convert arch/arm/tools/gen-mach-types Alexey Dobriyan
2021-03-01 10:19 ` Russell King - ARM Linux admin
2021-03-02 15:15 ` Alexey Dobriyan
2021-02-28 16:59 ` [PATCH 03/11] pragma once: convert arch/s390/tools/gen_facilities.c Alexey Dobriyan
2021-02-28 17:00 ` [PATCH 04/11] pragma once: convert drivers/gpu/drm/pl111/pl111_nomadik.h Alexey Dobriyan
2021-03-01 14:41 ` Linus Walleij
2021-02-28 17:01 ` [PATCH 05/11] pragma once: convert drivers/scsi/qla2xxx/qla_target.h Alexey Dobriyan
2021-02-28 22:07 ` Bart Van Assche
2021-02-28 17:02 ` [PATCH 06/11] pragma once: convert include/linux/cb710.h Alexey Dobriyan
2021-03-03 23:13 ` Michał Mirosław
2021-02-28 17:02 ` [PATCH 07/11] pragma once: convert kernel/time/timeconst.bc Alexey Dobriyan
2021-02-28 17:03 ` [PATCH 08/11] pragma once: convert scripts/atomic/ Alexey Dobriyan
2021-03-01 7:55 ` Peter Zijlstra
2021-02-28 17:04 ` [PATCH 09/11] pragma once: convert scripts/selinux/genheaders/genheaders.c Alexey Dobriyan
2021-02-28 18:37 ` Paul Moore
2021-02-28 18:57 ` Alexey Dobriyan
2021-02-28 17:05 ` [PATCH 10/11] pragma once: delete few backslashes Alexey Dobriyan
2021-03-01 8:54 ` Ido Schimmel
2021-03-02 19:00 ` Vineet Gupta
2021-03-04 14:22 ` Edward Cree
2021-03-23 10:09 ` Pavel Machek
2021-02-28 17:05 ` Alexey Dobriyan [this message]
2021-02-28 17:11 ` [PATCH 12/11] pragma once: scripted treewide conversion Alexey Dobriyan
2021-03-01 17:35 ` Darrick J. Wong
2021-02-28 17:46 ` [PATCH 00/11] pragma once: " Linus Torvalds
2021-02-28 19:34 ` Alexey Dobriyan
2021-02-28 20:00 ` Linus Torvalds
[not found] ` <877dmo10m3.fsf@tromey.com>
2021-03-03 20:17 ` Linus Torvalds
2021-03-04 13:55 ` David Laight
2021-03-04 20:16 ` Linus Torvalds
2021-03-05 9:19 ` David Laight
2021-03-05 21:23 ` Linus Torvalds
2021-03-06 13:07 ` Miguel Ojeda
2021-03-06 21:33 ` Linus Torvalds
2021-03-23 10:03 ` Pavel Machek
2021-03-01 0:29 ` Luc Van Oostenryck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YDvNbbHd2cKXlLme@localhost.localdomain \
--to=adobriyan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).