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: 48+ 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-02-28 16:59 ` Alexey Dobriyan
2021-03-01 10:19 ` Russell King - ARM Linux admin
2021-03-01 10:19 ` Russell King - ARM Linux admin
2021-03-02 15:15 ` Alexey Dobriyan
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-02-28 17:05 ` Alexey Dobriyan
2021-03-01 8:54 ` Ido Schimmel
2021-03-01 8:54 ` Ido Schimmel
2021-03-02 19:00 ` Vineet Gupta
2021-03-02 19:00 ` Vineet Gupta
2021-03-04 14:22 ` Edward Cree
2021-03-04 14:22 ` Edward Cree
2021-03-23 10:09 ` Pavel Machek
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-02-28 17:11 ` 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.