Block-Game-Client/runtime/pylibs/cleanup_src.py
2019-11-17 16:55:58 +00:00

297 lines
12 KiB
Python

import sys
import os
import re
import fnmatch
import shutil
from optparse import OptionParser
def strip_comments(src_dir):
"""Removes all C/C++/Java-style comments from files"""
regexps = {
# Remove C and C++ style comments
'comments': re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.MULTILINE | re.DOTALL),
# Remove trailing whitespace
'trailing': re.compile(r'[ \t]+$', re.MULTILINE),
# Remove repeated blank lines
'newlines': re.compile(r'^\n{2,}', re.MULTILINE),
}
def comment_replacer(match):
part = match.group(0)
if part.startswith('/'):
return ''
else:
return part
for path, _, filelist in os.walk(src_dir, followlinks=True):
for cur_file in fnmatch.filter(filelist, '*.java'):
src_file = os.path.normpath(os.path.join(path, cur_file))
tmp_file = src_file + '.tmp'
with open(src_file, 'r') as fh:
buf = fh.read()
buf = regexps['comments'].sub(comment_replacer, buf)
buf = regexps['trailing'].sub(r'', buf)
buf = regexps['newlines'].sub(r'\n', buf)
with open(tmp_file, 'w') as fh:
fh.write(buf)
shutil.move(tmp_file, src_file)
def src_cleanup(src_dir, fix_imports=True, fix_unicode=False, fix_charval=False, fix_pi=False, fix_round=False):
"""Do lots of random cleanups including stripping comments, trailing whitespace and extra blank lines"""
regexps = {
# Remove extra whitespace at start of file
'header': re.compile(r'^\s+'),
# Remove extra whitespace at end of file
'footer': re.compile(r'\s+$'),
# Remove trailing whitespace
'trailing': re.compile(r'[ \t]+$', re.MULTILINE),
# find package
'package': re.compile(r'^package (?P<package>[\w.]+);$', re.MULTILINE),
# find imports
'import': re.compile(r'^import (?:(?P<package>[\w.]*?)\.)?(?P<class>[\w]+);\n', re.MULTILINE),
# Remove repeated blank lines
'newlines': re.compile(r'^\n{2,}', re.MULTILINE),
# close up blanks in code like:
# {
#
# private
'blockstarts': re.compile(r'(?<={)\s+(?=\n[ \t]*\S)', re.MULTILINE),
# close up blanks in code like:
# }
#
# }
'blockends': re.compile(r'(?<=[;}])\s+(?=\n\s*})', re.MULTILINE),
# Remove GL comments and surrounding whitespace
'gl': re.compile(r'\s*/\*\s*GL_[^*]+\*/\s*'),
# convert unicode character constants back to integers
'unicode': re.compile(r"'\\u([0-9a-fA-F]{4})'"),
# strip out Character.valueof
'charval': re.compile(r"Character\.valueOf\(('.')\)"),
# 1.7976...E+308D to Double.MAX_VALUE
'maxD': re.compile(r'1\.7976[0-9]*[Ee]\+308[Dd]'),
# 3.1415...D to Math.PI
'piD': re.compile(r'3\.1415[0-9]*[Dd]'),
# 3.1415...F to (float)Math.PI
'piF': re.compile(r'3\.1415[0-9]*[Ff]'),
# 6.2831...D to (Math.PI * 2D)
'2piD': re.compile(r'6\.2831[0-9]*[Dd]'),
# 6.2831...F to ((float)Math.PI * 2F)
'2piF': re.compile(r'6\.2831[0-9]*[Ff]'),
# 1.5707...D to (Math.PI / 2D)
'pi2D': re.compile(r'1\.5707[0-9]*[Dd]'),
# 1.5707...F to ((float)Math.PI / 2F)
'pi2F': re.compile(r'1\.5707[0-9]*[Ff]'),
# 4.7123...D to (Math.PI * 3D / 2D)
'3pi2D': re.compile(r'4\.7123[0-9]*[Dd]'),
# 4.7123...F to ((float)Math.PI * 3F / 2F)
'3pi2F': re.compile(r'4\.7123[0-9]*[Ff]'),
# 0.7853...D to (Math.PI / 4D)
'pi4D': re.compile(r'0\.7853[0-9]*[Dd]'),
# 0.7853...F to ((float)Math.PI / 4F)
'pi4F': re.compile(r'0\.7853[0-9]*[Ff]'),
# 0.6283...D to (Math.PI / 5D)
'pi5D': re.compile(r'0\.6283[0-9]*[Dd]'),
# 0.6283...F to ((float)Math.PI / 5F)
'pi5F': re.compile(r'0\.6283[0-9]*[Ff]'),
# 57.295...D to (180D / Math.PI)
'180piD': re.compile(r'57\.295[0-9]*[Dd]'),
# 57.295...F to (180F / (float)Math.PI)
'180piF': re.compile(r'57\.295[0-9]*[Ff]'),
# 0.6981...D to (Math.PI * 2D / 9D)
'2pi9D': re.compile(r'0\.6981[0-9]*[Dd]'),
# 0.6981...F to ((float)Math.PI * 2F / 9F)
'2pi9F': re.compile(r'0\.6981[0-9]*[Ff]'),
# 0.3141...D to (Math.PI / 10D)
'pi10D': re.compile(r'0\.3141[0-9]*[Dd]'),
# 0.3141...F to ((float)Math.PI / 10F)
'pi10F': re.compile(r'0\.3141[0-9]*[Ff]'),
# 1.2566...D to (Math.PI * 2D / 5D)
'2pi5D': re.compile(r'1\.2566[0-9]*[Dd]'),
# 1.2566...F to ((float)Math.PI 2F / 5F)
'2pi5F': re.compile(r'1\.2566[0-9]*[Ff]'),
# 0.21991...D to (Math.PI * 7D / 100D)
'7pi100D': re.compile(r'0\.21991[0-9]*[Dd]'),
# 0.21991...F to ((float)Math.PI * 7F / 100F)
'7pi100F': re.compile(r'0\.21991[0-9]*[Ff]'),
# 5.8119...D to (Math.PI * 185D / 100D)
'185pi100D': re.compile(r'5\.8119[0-9]*[Dd]'),
# 5.8119...F to ((float)Math.PI * 185F / 100F)
'185pi100F': re.compile(r'0\.8119[0-9]*[Ff]'),
# 1.230000... to 1.23
'rounddown': re.compile(r'(?P<full>[0-9]+\.(?P<decimal>[0-9]+?)00000000[0-9]*)(?P<type>[Dd])'),
# 1.239999... to 1.24
'roundup': re.compile(r'(?P<full>[0-9]+\.(?P<decimal>[0-9]+?9)9999999[0-9]*)(?P<type>[Dd])'),
}
def unicode_replacer(match):
value = int(match.group(1), 16)
# work around the replace('\u00a7', '$') call in MinecraftServer and a couple of '\u0000'
if value > 255:
return str(value)
return match.group(0)
def rounddown_match(match):
# hackaround for GL11.glScalef(1.000001F, 1.000001F, 1.000001F) in WorldRenderer
if match.group(0) == '1.000001F':
return match.group(0)
val = float(match.group('full'))
return '%.*f%s' % (len(match.group('decimal')), val, match.group('type'))
def roundup_match(match):
val = float(match.group('full'))
return '%.*f%s' % (len(match.group('decimal')) - 1, val, match.group('type'))
# HINT: We pathwalk the sources
for path, _, filelist in os.walk(src_dir, followlinks=True):
for cur_file in fnmatch.filter(filelist, '*.java'):
src_file = os.path.normpath(os.path.join(path, cur_file))
tmp_file = src_file + '.tmp'
with open(src_file, 'r') as fh:
buf = fh.read()
if fix_imports:
# find the package for the current class
match = regexps['package'].search(buf)
if match:
package = match.group('package')
# if the import is for the same package as current class then delete it
def import_match(match):
if match.group('package') != package:
return match.group(0)
return ''
buf = regexps['import'].sub(import_match, buf)
buf = regexps['header'].sub(r'', buf)
buf = regexps['footer'].sub(r'\n', buf)
buf = regexps['trailing'].sub(r'', buf)
buf = regexps['newlines'].sub(r'\n', buf)
buf = regexps['blockstarts'].sub(r'', buf)
buf = regexps['blockends'].sub(r'', buf)
buf = regexps['gl'].sub(r'', buf)
buf = regexps['maxD'].sub(r'Double.MAX_VALUE', buf)
if fix_unicode:
buf = regexps['unicode'].sub(unicode_replacer, buf)
if fix_charval:
buf = regexps['charval'].sub(r'\1', buf)
if fix_pi:
buf = regexps['piD'].sub(r'Math.PI', buf)
buf = regexps['piF'].sub(r'(float)Math.PI', buf)
buf = regexps['2piD'].sub(r'(Math.PI * 2D)', buf)
buf = regexps['2piF'].sub(r'((float)Math.PI * 2F)', buf)
buf = regexps['pi2D'].sub(r'(Math.PI / 2D)', buf)
buf = regexps['pi2F'].sub(r'((float)Math.PI / 2F)', buf)
buf = regexps['3pi2D'].sub(r'(Math.PI * 3D / 2D)', buf)
buf = regexps['3pi2F'].sub(r'((float)Math.PI * 3F / 2F)', buf)
buf = regexps['pi4D'].sub(r'(Math.PI / 4D)', buf)
buf = regexps['pi4F'].sub(r'((float)Math.PI / 4F)', buf)
buf = regexps['pi5D'].sub(r'(Math.PI / 5D)', buf)
buf = regexps['pi5F'].sub(r'((float)Math.PI / 5F)', buf)
buf = regexps['180piD'].sub(r'(180D / Math.PI)', buf)
buf = regexps['180piF'].sub(r'(180F / (float)Math.PI)', buf)
buf = regexps['2pi9D'].sub(r'(Math.PI * 2D / 9D)', buf)
buf = regexps['2pi9F'].sub(r'((float)Math.PI * 2F / 9F)', buf)
buf = regexps['pi10D'].sub(r'(Math.PI / 10D)', buf)
buf = regexps['pi10F'].sub(r'((float)Math.PI / 10F)', buf)
buf = regexps['2pi5D'].sub(r'(Math.PI * 2D / 5D)', buf)
buf = regexps['2pi5F'].sub(r'((float)Math.PI * 2F / 5F)', buf)
buf = regexps['7pi100D'].sub(r'(Math.PI * 7D / 100D)', buf)
buf = regexps['7pi100F'].sub(r'((float)Math.PI * 7F / 100F)', buf)
buf = regexps['185pi100D'].sub(r'(Math.PI * 185D / 100D)', buf)
buf = regexps['185pi100F'].sub(r'((float)Math.PI * 185F / 100F)', buf)
if fix_round:
buf = regexps['rounddown'].sub(rounddown_match, buf)
buf = regexps['roundup'].sub(roundup_match, buf)
with open(tmp_file, 'w') as fh:
fh.write(buf)
shutil.move(tmp_file, src_file)
def cleanup_src(src_dir, clean_comments=True, clean_src=True, fix_imports=True, fix_unicode=False, fix_charval=False,
fix_pi=False, fix_round=False):
if clean_comments:
strip_comments(src_dir)
if clean_src:
src_cleanup(src_dir, fix_imports=fix_imports, fix_unicode=fix_unicode, fix_charval=fix_charval, fix_pi=fix_pi,
fix_round=fix_round)
def main():
usage = 'usage: %prog [options] src_dir'
version = '%prog 6.0'
parser = OptionParser(version=version, usage=usage)
parser.add_option('-c', '--nocomment', action='store_false', dest='clean_comments', help="don't strip comments",
default=True)
parser.add_option('-s', '--nocleanup', action='store_false', dest='clean_src', help="don't cleanup source",
default=True)
parser.add_option('-i', '--imports', action='store_true', dest='fix_imports', help='cleanup unneeded imports',
default=False)
parser.add_option('-u', '--unicode', action='store_true', dest='fix_unicode',
help='convert unicode character constant to integer', default=False)
parser.add_option('-v', '--charval', action='store_true', dest='fix_charval',
help='convert Character.valueof to constant', default=False)
parser.add_option('-p', '--pi', action='store_true', dest='fix_pi',
help='convert pi constants', default=False)
parser.add_option('-r', '--round', action='store_true', dest='fix_round',
help='round long float and double constants', default=False)
options, args = parser.parse_args()
if len(args) != 1:
print >> sys.stderr, 'src_dir required'
sys.exit(1)
cleanup_src(args[0], clean_comments=options.clean_comments, clean_src=options.clean_src,
fix_imports=options.fix_imports, fix_unicode=options.fix_unicode, fix_charval=options.fix_charval,
fix_pi=options.fix_pi, fix_round=options.fix_round)
if __name__ == '__main__':
main()