summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]scripts/build/makedep.py967
-rw-r--r--scripts/build/makelist.py167
-rw-r--r--scripts/genie.lua8
-rw-r--r--scripts/minimaws/minimaws.wsgi7
-rw-r--r--scripts/src/main.lua8
-rw-r--r--src/tools/srcclean.cpp145
6 files changed, 858 insertions, 444 deletions
diff --git a/scripts/build/makedep.py b/scripts/build/makedep.py
index 30c1d7018c4..63ead75d1c7 100644..100755
--- a/scripts/build/makedep.py
+++ b/scripts/build/makedep.py
@@ -1,264 +1,737 @@
#!/usr/bin/python
##
## license:BSD-3-Clause
-## copyright-holders:Miodrag Milanovic
-
-from __future__ import with_statement
+## copyright-holders:Vas Crabb
+import argparse
import io
+import os.path
import sys
-## to ignore include of emu.h add it always to list
-files_included = ['src/emu/emu.h']
+class ParserBase(object):
+ def process_lines(self, f):
+ self.input_line = 1
+ for line in f:
+ pos = 0
+ start = 0
+ if line.endswith('\n'):
+ line = line[:-1]
+ used = 0
+ while used is not None:
+ start += used
+ used = self.processors[self.parse_state](line[start:])
+ self.input_line += 1
+
+
+class CppParser(ParserBase):
+ TOKEN_LEAD = frozenset(
+ [chr(x) for x in range(ord('A'), ord('Z') + 1)] +
+ [chr(x) for x in range(ord('a'), ord('z') + 1)] +
+ ['_'])
+ TOKEN_CONTINUATION = frozenset(
+ [chr(x) for x in range(ord('0'), ord('9') + 1)] +
+ [chr(x) for x in range(ord('A'), ord('Z') + 1)] +
+ [chr(x) for x in range(ord('a'), ord('z') + 1)] +
+ ['_'])
+ HEXADECIMAL_DIGIT = frozenset(
+ [chr(x) for x in range(ord('0'), ord('9') + 1)] +
+ [chr(x) for x in range(ord('A'), ord('F') + 1)] +
+ [chr(x) for x in range(ord('a'), ord('f') + 1)])
+
+ class Handler(object):
+ def line(self, text):
+ pass
+
+ def comment(self, text):
+ pass
+
+ def line_comment(self, text):
+ pass
+
+ class ParseState(object):
+ DEFAULT = 0
+ COMMENT = 1
+ LINE_COMMENT = 2
+ TOKEN = 3
+ STRING_CONSTANT = 4
+ CHARACTER_CONSTANT = 5
+ NUMERIC_CONSTANT = 6
+
+ def __init__(self, handler, **kwargs):
+ super(CppParser, self).__init__(**kwargs)
+ self.handler = handler
+ self.processors = {
+ self.ParseState.DEFAULT: self.process_default,
+ self.ParseState.COMMENT: self.process_comment,
+ self.ParseState.LINE_COMMENT: self.process_line_comment,
+ self.ParseState.TOKEN: self.process_token,
+ self.ParseState.STRING_CONSTANT: self.process_text,
+ self.ParseState.CHARACTER_CONSTANT: self.process_text,
+ self.ParseState.NUMERIC_CONSTANT: self.process_numeric }
+
+ def parse(self, f):
+ self.parse_state = self.ParseState.DEFAULT
+ self.comment_line = None
+ self.lead_digit = None
+ self.radix = None
+ self.line_buffer = ''
+ self.comment_buffer = ''
+ self.process_lines(f)
+ if self.parse_state == self.ParseState.COMMENT:
+ raise Exception('unterminated multi-line comment beginning on line %d' % (self.comment_line, ))
+ elif self.parse_state == self.ParseState.CHARACTER_CONSTANT:
+ raise Exception('unterminated character literal on line %d' % (self.input_line, ))
+ elif self.parse_state == self.ParseState.STRING_CONSTANT:
+ raise Exception('unterminated string literal on line %d' % (self.input_line, ))
+
+ def process_default(self, line):
+ escape = False
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if (ch == '"') or (ch == "'"):
+ self.parse_state = self.ParseState.STRING_CONSTANT if ch == '"' else self.ParseState.CHARACTER_CONSTANT
+ self.line_buffer += line[:pos + 1]
+ return pos + 1
+ elif ch == '*':
+ if escape:
+ self.parse_state = self.ParseState.COMMENT
+ self.comment_line = self.input_line
+ self.line_buffer += line[:pos - 1] + ' '
+ return pos + 1
+ elif ch == '/':
+ if escape:
+ self.parse_state = self.ParseState.LINE_COMMENT
+ self.handler.line(self.line_buffer + line[:pos - 1] + ' ')
+ self.line_buffer = ''
+ return pos + 1
+ elif ch in self.TOKEN_LEAD:
+ self.parse_state = self.ParseState.TOKEN
+ self.line_buffer += line[:pos]
+ return pos
+ elif (ch >= '0') and (ch <= '9'):
+ self.parse_state = self.ParseState.NUMERIC_CONSTANT
+ self.line_buffer += line[:pos]
+ return pos
+ escape = ch == '/'
+ pos += 1
+ if line.endswith('\\'):
+ self.line_buffer += line[:-1]
+ else:
+ self.handler.line(self.line_buffer + line)
+ self.line_buffer = ''
+
+ def process_comment(self, line):
+ escape = False
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if escape and (ch == '/'):
+ self.parse_state = self.ParseState.DEFAULT
+ self.comment_line = None
+ self.handler.comment(self.comment_buffer + line[:pos - 1])
+ self.comment_buffer = ''
+ return pos + 1
+ escape = ch == '*'
+ pos += 1
+ if line.endswith('\\'):
+ self.comment_buffer += line[:-1]
+ else:
+ self.comment_buffer += line + '\n'
+
+ def process_line_comment(self, line):
+ self.parse_state = self.ParseState.DEFAULT
+ self.handler.line_comment(self.comment_buffer + line)
+ self.comment_buffer = ''
+
+ def process_token(self, line):
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if ch not in self.TOKEN_CONTINUATION:
+ self.parse_state = self.ParseState.DEFAULT
+ self.line_buffer += line[:pos]
+ return pos
+ pos += 1
+ self.parse_state = self.ParseState.DEFAULT
+ self.handler.line(self.line_buffer + line)
+ self.line_buffer = ''
+
+ def process_text(self, line):
+ quote = '"' if self.parse_state == self.ParseState.STRING_CONSTANT else "'"
+ escape = False
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if (ch == quote) and not escape:
+ self.parse_state = self.ParseState.DEFAULT
+ self.line_buffer += line[:pos + 1]
+ return pos + 1
+ escape = (ch == '\\') and not escape
+ pos += 1
+ if line.endswith('\\'):
+ self.line_buffer += line[:-1]
+ else:
+ t = 'string' if self.ParseState == self.ParseState.STRING_CONSTANT else 'character'
+ raise Exception('unterminated %s literal on line %d' % (t, self.input_line))
+
+ def process_numeric(self, line):
+ escape = False
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if self.lead_digit is None:
+ self.lead_digit = ch
+ if ch != '0':
+ self.radix = 10
+ elif self.radix is None:
+ if ch == "'":
+ if escape:
+ raise Exception('adjacent digit separators on line %d' % (self.input_line, ))
+ else:
+ escape = True
+ elif (ch == 'B') or (ch == 'b'):
+ self.radix = 2
+ elif (ch == 'X') or (ch == 'x'):
+ self.radix = 16
+ elif (ch >= '0') and (ch <= '7'):
+ self.radix = 8
+ else:
+ self.parse_state = self.ParseState.DEFAULT # probably an argument to a token-pasting or stringifying macro
+ else:
+ if ch == "'":
+ if escape:
+ raise Exception('adjacent digit separators on line %d' % (self.input_line, ))
+ else:
+ escape = True
+ else:
+ escape = False
+ if self.radix == 2:
+ if (ch < '0') or (ch > '1'):
+ self.parse_state = self.ParseState.DEFAULT
+ elif self.radix == 8:
+ if (ch < '0') or (ch > '7'):
+ self.parse_state = self.ParseState.DEFAULT
+ elif self.radix == 10:
+ if (ch < '0') or (ch > '9'):
+ self.parse_state = self.ParseState.DEFAULT
+ elif self.radix == 16:
+ if ch not in self.HEXADECIMAL_DIGIT:
+ self.parse_state = self.ParseState.DEFAULT
+ if self.parse_state == self.ParseState.DEFAULT:
+ self.lead_digit = None
+ self.radix = None
+ self.line_buffer += line[:pos]
+ return pos
+ pos += 1
+ self.parse_state = self.ParseState.DEFAULT
+ self.lead_digit = None
+ self.radix = None
+ self.handler.line(self.line_buffer + line)
+ self.line_buffer = ''
+
+
+class LuaParser(ParserBase):
+ class Handler(object):
+ def short_comment(self, text):
+ pass
+
+ def long_comment_start(self, level):
+ pass
+
+ def long_comment_line(self, text):
+ pass
+
+ def long_comment_end(self):
+ pass
+
+ class ParseState(object):
+ DEFAULT = 0
+ SHORT_COMMENT = 1
+ LONG_COMMENT = 2
+ STRING_CONSTANT = 3
+ LONG_STRING_CONSTANT = 4
+
+ def __init__(self, handler, **kwargs):
+ super(LuaParser, self).__init__(**kwargs)
+ self.handler = handler
+ self.processors = {
+ self.ParseState.DEFAULT: self.process_default,
+ self.ParseState.SHORT_COMMENT: self.process_short_comment,
+ self.ParseState.LONG_COMMENT: self.process_long_comment,
+ self.ParseState.STRING_CONSTANT: self.process_string_constant,
+ self.ParseState.LONG_STRING_CONSTANT: self.process_long_string_constant }
+
+ def parse(self, f):
+ self.parse_state = self.ParseState.DEFAULT
+ self.long_bracket_level = None
+ self.escape = False
+ self.block_line = None
+ self.block_level = None
+ self.string_quote = None
+ self.process_lines(f)
+ if self.parse_state == self.ParseState.LONG_COMMENT:
+ raise Exception('unterminated long comment beginning on line %d' % (self.block_line, ));
+ elif self.parse_state == self.ParseState.STRING_CONSTANT:
+ raise Exception('unterminated string literal on line %d' % (self.input_line, ));
+ elif self.parse_state == self.ParseState.LONG_STRING_CONSTANT:
+ raise Exception('unterminated long string literal beginning on line %d' % (self.block_line, ));
+
+ def process_default(self, line):
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if (ch == '"') or (ch == "'"):
+ self.string_quote = ch
+ self.parse_state = self.ParseState.STRING_CONSTANT
+ self.long_bracket_level = None
+ self.escape = False
+ return pos + 1;
+ elif (ch == '-') and self.escape:
+ self.parse_state = self.ParseState.SHORT_COMMENT
+ self.long_bracket_level = None
+ self.escape = False
+ return pos + 1
+ elif self.long_bracket_level is not None:
+ if ch == '=':
+ self.long_bracket_level += 1
+ elif ch == '[':
+ self.block_line = self.input_line
+ self.block_level = self.long_bracket_level
+ self.parse_state = self.ParseState.LONG_STRING_CONSTANT
+ self.long_bracket_level = None
+ self.escape = False
+ return pos + 1
+ else:
+ self.long_bracket_level = None
+ elif ch == '[':
+ self.long_bracket_level = 0
+ self.escape = ch == '-'
+ pos += 1
+ self.escape = False
+
+ def process_short_comment(self, line):
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if self.long_bracket_level is not None:
+ if ch == '=':
+ self.long_bracket_level += 1
+ elif ch == '[':
+ self.block_line = self.input_line
+ self.block_level = self.long_bracket_level
+ self.parse_state = self.ParseState.LONG_COMMENT
+ self.long_bracket_level = None
+ self.handler.long_comment_start(self.block_level)
+ return pos + 1
+ else:
+ self.long_bracket_level = None
+ elif ch == '[':
+ self.long_bracket_level = 0
+ if self.long_bracket_level is None:
+ self.handler.short_comment(line[pos:])
+ self.parse_state = self.ParseState.DEFAULT
+ return None
+ pos += 1
+ self.handler.short_comment(line)
+ self.parse_state = self.ParseState.DEFAULT
+
+ def process_long_comment(self, line):
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if self.long_bracket_level is not None:
+ if ch == '=':
+ self.long_bracket_level += 1
+ elif ch == ']':
+ if self.long_bracket_level == self.block_level:
+ if self.parse_state == self.ParseState.LONG_COMMENT:
+ self.handler.long_comment_line(line[:endpos])
+ self.handler.long_comment_end()
+ self.parse_state = self.ParseState.DEFAULT
+ return pos + 1
+ else:
+ self.long_bracket_level = 0
+ else:
+ self.long_bracket_level = None
+ elif ch == ']':
+ endpos = pos
+ self.long_bracket_level = 0
+ pos += 1
+ self.long_bracket_level = None
+ self.handler.long_comment_line(line)
+
+ def process_string_constant(self, line):
+ pos = 0
+ length = len(line)
+ while pos < length:
+ ch = line[pos]
+ if (ch == self.string_quote) and not self.escape:
+ self.parse_state = self.ParseState.DEFAULT
+ return pos + 1
+ self.escape = (ch == '\\') and not self.escape
+ pos += 1
+ if not self.escape:
+ raise Exception('unterminated string literal on line %d' % (self.input_line, ));
-include_dirs = ['src/emu/', 'src/devices/', 'src/mame/', 'src/lib/']
+ def process_long_string_constant(self, line):
+ self.process_long_comment(line) # this works because they're both closed by a matching long bracket
-mappings = dict()
-deps_files_included = [ ]
+class DriverFilter(object):
+ DRIVER_CHARS = frozenset(
+ [chr(x) for x in range(ord('0'), ord('9') + 1)] +
+ [chr(x) for x in range(ord('a'), ord('z') + 1)] +
+ ['_'])
-deps_include_dirs = ['src/mame/']
+ def __init__(self, options, **kwargs):
+ super(DriverFilter, self).__init__(**kwargs)
+ self.parse_filter(options.filter)
+ self.parse_list(options.list)
-components = [ ]
+ def write_source(self, f):
+ f.write(
+ '#include "emu.h"\n' \
+ '\n' \
+ '#include "drivenum.h"\n' \
+ '\n')
+ for driver in self.drivers:
+ f.write('GAME_EXTERN(%s);\n' % driver)
+ f.write(
+ '\n' \
+ 'game_driver const *const driver_list::s_drivers_sorted[%d] =\n' \
+ '{\n' % (len(self.drivers), ))
+ for driver in self.drivers:
+ f.write('\t&GAME_NAME(%s),\n' % driver)
+ f.write(
+ '};\n' \
+ '\n' \
+ 'std::size_t const driver_list::s_driver_count = %d;\n' % (len(self.drivers), ))
-drivers = [ ]
+ def parse_filter(self, path):
+ def do_parse(p):
+ def line_hook(text):
+ text = text.strip()
+ if text.startswith('#'):
+ do_parse(os.path.join(os.path.dirname(n), text[1:].lstrip()))
+ elif text.startswith('+'):
+ text = text[1:].lstrip()
+ if not text:
+ sys.stderr.write('%s:%s: Empty driver name\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ elif not all(x in self.DRIVER_CHARS for x in text):
+ sys.stderr.write('%s:%s: Invalid character in driver name "%s"\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ includes.add(text)
+ elif text.startswith('-'):
+ text = text[1:].lstrip()
+ if not text:
+ sys.stderr.write('%s:%s: Empty driver name\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ elif not all(x in self.DRIVER_CHARS for x in text):
+ sys.stderr.write('%s:%s: Invalid character in driver name "%s"\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ excludes.add(text)
+ elif text:
+ sources.add(text)
-def file_exists(root, srcfile, folder, inc_dir):
- includes = [ folder ]
- includes.extend(inc_dir)
- for line in includes:
+ n = os.path.normpath(p)
+ if n not in filters:
+ filters.add(n)
+ try:
+ f = io.open(n, 'r', encoding='utf-8')
+ except IOError:
+ sys.stderr.write('Unable to open filter file "%s"\n' % (p, ))
+ sys.exit(1)
+ with f:
+ handler = CppParser.Handler()
+ handler.line = line_hook
+ parser = CppParser(handler)
+ try:
+ parser.parse(f)
+ except IOError:
+ sys.stderr.write('Error reading filter file "%s"\n' % (p, ))
+ sys.exit(1)
+ except Exception as e:
+ sys.stderr.write('Error parsing filter file "%s": %s\n' % (p, e))
+ sys.exit(1)
+
+ sources = set()
+ includes = set()
+ excludes = set()
+ filters = set()
+ if path is not None:
+ do_parse(path)
+ sys.stderr.write('%d source file(s) found\n' % (len(sources), ))
+ self.sources = frozenset(sources)
+ self.includes = frozenset(includes - excludes)
+ self.excludes = frozenset(excludes)
+
+ def parse_list(self, path):
+ def do_parse(p):
+ def line_hook(text):
+ text = text.strip()
+ if text.startswith('#'):
+ do_parse(os.path.join(os.path.dirname(n), text[1:].lstrip()))
+ elif text.startswith('@'):
+ parts = text[1:].lstrip().split(':', 1)
+ parts[0] = parts[0].strip()
+ if (parts[0] == 'source') and (len(parts) == 2):
+ parts[1] = parts[1].strip()
+ if not parts[1]:
+ sys.stderr.write('%s:%s: Empty source file name "%s"\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ elif self.sources:
+ state['includesrc'] = parts[1] in self.sources
+ else:
+ sys.stderr.write('%s:%s: Unsupported directive "%s"\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ elif text:
+ if not all(x in self.DRIVER_CHARS for x in text):
+ sys.stderr.write('%s:%s: Invalid character in driver name "%s"\n' % (p, parser.input_line, text))
+ sys.exit(1)
+ elif state['includesrc'] and (text not in self.excludes):
+ drivers.add(text)
+
+ n = os.path.normpath(p)
+ if n not in lists:
+ lists.add(n)
+ try:
+ f = io.open(n, 'r', encoding='utf-8')
+ except IOError:
+ sys.stderr.write('Unable to open list file "%s"\n' % (p, ))
+ sys.exit(1)
+ with f:
+ handler = CppParser.Handler()
+ handler.line = line_hook
+ parser = CppParser(handler)
+ try:
+ parser.parse(f)
+ except IOError:
+ sys.stderr.write('Error reading list file "%s"\n' % (p, ))
+ sys.exit(1)
+ except Exception as e:
+ sys.stderr.write('Error parsing list file "%s": %s\n' % (p, e))
+ sys.exit(1)
+
+ lists = set()
+ drivers = set()
+ state = object()
+ state = { 'includesrc': True }
+ do_parse(path)
+ for driver in self.includes:
+ drivers.add(driver)
+ sys.stderr.write('%d driver(s) found\n' % (len(drivers), ))
+ drivers.add('___empty')
+ self.drivers = sorted(drivers)
+
+
+def split_path(path):
+ path = os.path.normpath(path)
+ result = [ ]
+ while True:
+ dirname, basename = os.path.split(path)
+ if dirname == path:
+ result.insert(0, dirname)
+ return result
+ elif basename == path:
+ result.insert(0, basename)
+ return result
+ else:
+ result.insert(0, basename)
+ path = dirname
+
+
+def parse_command_line():
+ parser = argparse.ArgumentParser()
+ subparsers = parser.add_subparsers(title='commands', dest='command', metavar='<command>')
+
+ subparser = subparsers.add_parser('sourcesproject', help='generate project directives for source files')
+ subparser.add_argument('-r', '--root', metavar='<srcroot>', default='.', help='path to emulator source root (defaults to working directory)')
+ subparser.add_argument('-t', '--target', metavar='<target>', required=True, help='generated emulator target name')
+ subparser.add_argument('sources', metavar='<srcfile>', nargs='+', help='source files to include')
+
+ subparser = subparsers.add_parser('sourcesfilter', help='generate driver filter for source files')
+ subparser.add_argument('sources', metavar='<srcfile>', nargs='+', help='source files to include')
+
+ subparser = subparsers.add_parser('driverlist', help='generate driver list source')
+ subparser.add_argument('-f', '--filter', metavar='<fltfile>', help='input filter file')
+ subparser.add_argument('list', metavar='<lstfile>', help='input list file')
+
+ return parser.parse_args()
+
+
+def collect_lua_directives(options):
+ def short_comment_hook(text):
+ if text.startswith('@'):
+ name, action = text[1:].rstrip().rsplit(',', 1)
+ if name not in result:
+ result[name] = [ ]
+ result[name].append(action)
+
+ base = os.path.join(options.root, 'scripts', 'src')
+ result = { }
+ handler = LuaParser.Handler()
+ handler.short_comment = short_comment_hook
+ parser = LuaParser(handler)
+ for name in ('bus', 'cpu', 'machine', 'sound', 'video', 'formats'):
+ path = os.path.join(base, name + '.lua')
try:
- fp = open(root + line + srcfile, 'r')
- fp.close()
- return line + srcfile
+ f = io.open(path, 'r', encoding='utf-8')
except IOError:
- pass
- return ''
-
-def add_c_if_exists(root, fullname):
- try:
- fp = open(root + fullname, 'r')
- fp.close()
- deps_files_included.append(fullname)
- except IOError:
- pass
-
-def add_rest_if_exists(root, srcfile,folder):
- t = srcfile.rsplit('/', 2)
- if t[1]=='includes':
- t[2] = t[2].replace('.h','.cpp')
- t[1] = 'drivers'
- add_c_if_exists(root,"/".join(t))
- parse_file_for_deps(root, "/".join(t), folder)
- t[1] = 'machine'
- add_c_if_exists(root,"/".join(t))
- parse_file_for_deps(root, "/".join(t), folder)
- t[1] = 'video'
- add_c_if_exists(root,"/".join(t))
- parse_file_for_deps(root, "/".join(t), folder)
- t[1] = 'audio'
- add_c_if_exists(root,"/".join(t))
- parse_file_for_deps(root, "/".join(t), folder)
-
-def parse_file_for_deps(root, srcfile, folder):
- try:
- fp = io.open(root + srcfile, 'r', encoding='utf-8')
- except IOError:
- return 1
- in_comment = 0
- linenum = 0
- with fp:
- for line in fp.readlines():
- content = ''
- linenum+=1
- srcptr = 0
- while srcptr < len(line):
- c = line[srcptr]
- srcptr+=1
- if ord(c)==13 or ord(c)==10:
- if ord(c)==13 and ord(line[srcptr])==10:
- srcptr+=1
- continue
- if c==' ' or ord(c)==9:
- continue
- if in_comment==1 and c=='*' and line[srcptr]=='/' :
- srcptr+=1
- in_comment = 0
- continue
- if in_comment:
- continue
- if c=='/' and line[srcptr]=='*' :
- srcptr+=1
- in_comment = 1
- continue
- if c=='/' and line[srcptr]=='/' :
- break
- content += c
- content = content.strip()
- if len(content)>0:
- if content.startswith('#include'):
- name = content[8:]
- name = name.replace('"','')
- fullname = file_exists(root, name, folder,deps_include_dirs)
- if fullname in deps_files_included:
- continue
- if fullname!='':
- deps_files_included.append(fullname)
- add_c_if_exists(root, fullname.replace('.h','.cpp'))
- add_rest_if_exists(root, fullname,folder)
- newfolder = fullname.rsplit('/', 1)[0] + '/'
- parse_file_for_deps(root, fullname, newfolder)
- continue
- return 0
-
-def parse_file(root, srcfile, folder):
- try:
- fp = io.open(root + srcfile, 'r', encoding='utf-8')
- except IOError:
- return 1
- in_comment = 0
- linenum = 0
- with fp:
- for line in fp.readlines():
- content = ''
- linenum+=1
- srcptr = 0
- while srcptr < len(line):
- c = line[srcptr]
- srcptr+=1
- if ord(c)==13 or ord(c)==10:
- if ord(c)==13 and ord(line[srcptr])==10:
- srcptr+=1
- continue
- if c==' ' or ord(c)==9:
- continue
- if in_comment==1 and c=='*' and line[srcptr]=='/' :
- srcptr+=1
- in_comment = 0
- continue
- if in_comment:
- continue
- if c=='/' and line[srcptr]=='*' :
- srcptr+=1
- in_comment = 1
- continue
- if c=='/' and line[srcptr]=='/' :
- break
- content += c
- content = content.strip()
- if len(content)>0:
- if content.startswith('#include'):
- name = content[8:]
- name = name.replace('"','')
- fullname = file_exists(root, name, folder,include_dirs)
- if fullname in files_included:
- continue
- if "src/lib/netlist/" in fullname:
- continue
- if fullname!='':
- if fullname in mappings.keys():
- if not(mappings[fullname] in components):
- components.append(mappings[fullname])
- files_included.append(fullname)
- newfolder = fullname.rsplit('/', 1)[0] + '/'
- parse_file(root, fullname, newfolder)
- if (fullname.endswith('.h') and not("src/emu" in fullname) and not("src/devices" in fullname) and not("src/lib" in fullname) and not("src/osd" in fullname)):
- parse_file_for_deps(root, fullname.replace('.h','.cpp'), newfolder)
- elif fullname.endswith('.h'):
- parse_file(root, fullname.replace('.h','.cpp'), newfolder)
- continue
- return 0
-
-def parse_file_for_drivers(root, srcfile):
- srcfile = srcfile.replace('\\','/')
- if srcfile.startswith('src/mame/drivers'):
- splitname = srcfile.split('/', 4)
- drivers.append(splitname[3])
- return 0
-
-def parse_lua_file(srcfile):
- try:
- fp = io.open(srcfile, 'r', encoding='utf-8')
- except IOError:
- sys.stderr.write("Unable to open source file '%s'\n" % srcfile)
- return 1
- with fp:
- for line in fp.readlines():
- content = line.strip()
- if len(content)>0:
- if content.startswith('--@'):
- name = content[3:]
- mappings[name.rsplit(',', 1)[0]] = name.rsplit(',', 1)[1]
- return 0
-
-if len(sys.argv) < 5:
- print('Usage:')
- print(' makedep <root> <source.c> <type> <target>')
- sys.exit(0)
-
-root = sys.argv[1] + '/'
-
-parse_lua_file(root +'scripts/src/bus.lua')
-parse_lua_file(root +'scripts/src/cpu.lua')
-parse_lua_file(root +'scripts/src/machine.lua')
-parse_lua_file(root +'scripts/src/sound.lua')
-parse_lua_file(root +'scripts/src/video.lua')
-parse_lua_file(root +'scripts/src/formats.lua')
-
-for filename in sys.argv[2].rsplit(',') :
- deps_files_included.append(filename.replace('\\','/'))
- parse_file_for_deps(root,filename,'')
-
-for filename in deps_files_included:
- parse_file(root,filename,'')
-
-for filename in sys.argv[2].rsplit(',') :
- parse_file_for_drivers(root,filename)
-
-# display output
-if sys.argv[3]=='drivers':
- #output the list of externs first
- for drv in sorted(drivers):
- print(drv)
- print("")
-
-if sys.argv[3]=='target':
- for line in components:
- sys.stdout.write("%s\n" % line)
- sys.stdout.write('\n')
- sys.stdout.write('function createProjects_mame_%s(_target, _subtarget)\n' % sys.argv[4])
- sys.stdout.write(' project ("mame_%s")\n' % sys.argv[4])
- sys.stdout.write(' targetsubdir(_target .."_" .. _subtarget)\n')
- sys.stdout.write(' kind (LIBTYPE)\n')
- sys.stdout.write(' uuid (os.uuid("drv-mame-%s"))\n' % sys.argv[4])
- sys.stdout.write(' addprojectflags()\n')
- sys.stdout.write(' \n')
- sys.stdout.write(' includedirs {\n')
- sys.stdout.write(' MAME_DIR .. "src/osd",\n')
- sys.stdout.write(' MAME_DIR .. "src/emu",\n')
- sys.stdout.write(' MAME_DIR .. "src/devices",\n')
- sys.stdout.write(' MAME_DIR .. "src/mame",\n')
- sys.stdout.write(' MAME_DIR .. "src/lib",\n')
- sys.stdout.write(' MAME_DIR .. "src/lib/util",\n')
- sys.stdout.write(' MAME_DIR .. "src/lib/netlist",\n')
- sys.stdout.write(' MAME_DIR .. "3rdparty",\n')
- sys.stdout.write(' GEN_DIR .. "mame/layout",\n')
- sys.stdout.write(' ext_includedir("flac"),\n')
- sys.stdout.write(' ext_includedir("glm"),\n')
- sys.stdout.write(' ext_includedir("jpeg"),\n')
- sys.stdout.write(' ext_includedir("rapidjson"),\n')
- sys.stdout.write(' ext_includedir("zlib"),\n')
- sys.stdout.write(' }\n')
- sys.stdout.write('\n')
- sys.stdout.write(' files{\n')
- for line in deps_files_included:
- sys.stdout.write(' MAME_DIR .. "%s",\n' % line)
- sys.stdout.write(' }\n')
- sys.stdout.write('end\n')
- sys.stdout.write('\n')
- sys.stdout.write('function linkProjects_mame_%s(_target, _subtarget)\n' % sys.argv[4])
- sys.stdout.write(' links {\n')
- sys.stdout.write(' "mame_%s",\n' % sys.argv[4])
- sys.stdout.write(' }\n')
- sys.stdout.write('end\n')
+ sys.stderr.write('Unable to open source file "%s"\n' % (path, ))
+ sys.exit(1)
+ try:
+ with f:
+ parser.parse(f)
+ except IOError:
+ sys.stderr.write('Error reading source file "%s"\n' % (path, ))
+ sys.exit(1)
+ except Exception as e:
+ sys.stderr.write('Error parsing source file "%s": %s\n' % (path, e))
+ sys.exit(1)
+ return result
+
+
+def scan_source_dependencies(options):
+ def locate_include(path):
+ relative = os.path.join(*path)
+ for incdir in roots:
+ if os.path.isfile(os.path.join(os.path.join(options.root, *incdir), relative)):
+ return tuple(incdir + path)
+
+ def test_siblings(relative, basename):
+ pathbase = '/'.join(relative) + '/'
+ dirname = os.path.join(options.root, *relative)
+ for ext in ('.cpp', '.ipp', '.hxx'):
+ path = pathbase + basename + ext
+ if (path not in seen) and os.path.isfile(os.path.join(dirname, basename + ext)):
+ remaining.append(path)
+ seen.add(path)
+
+ def line_hook(text):
+ text = text.lstrip()
+ if text.startswith('#'):
+ text = text[1:].lstrip()
+ if text.startswith('include'):
+ text = text[7:]
+ if text[:1].isspace():
+ text = text.strip()
+ if (len(text) > 2) and (text[0] == '"') and (text[-1] == '"'):
+ components = locate_include(tuple(x for x in text[1:-1].split('/') if x))
+ if components:
+ path = '/'.join(components)
+ if path not in seen:
+ remaining.append(path)
+ seen.add(path)
+ base, ext = os.path.splitext(components[-1])
+ if ext.lower().startswith('.h'):
+ components = components[:-1]
+ test_siblings(components, base)
+ if components == ('src', 'mame', 'includes'):
+ for aspect in ('audio', 'drivers', 'video', 'machine'):
+ test_siblings(('src', 'mame', aspect), base)
+
+ handler = CppParser.Handler()
+ handler.line = line_hook
+ parser = CppParser(handler)
+ seen = set('/'.join(x for x in split_path(source) if x) for source in options.sources)
+ remaining = list(seen)
+ while remaining:
+ source = remaining.pop()
+ components = tuple(source.split('/'))
+ roots = (components[:-1], ('src', 'devices'), ('src', 'mame'), ('src', 'lib'))
+ try:
+ f = io.open(os.path.join(options.root, *components), 'r', encoding='utf-8')
+ except IOError:
+ sys.stderr.write('Unable to open source file "%s"\n' % (source, ))
+ sys.exit(1)
+ try:
+ with f:
+ parser.parse(f)
+ except IOError:
+ sys.stderr.write('Error reading source file "%s"\n' % (source, ))
+ sys.exit(1)
+ except Exception as e:
+ sys.stderr.write('Error parsing source file "%s": %s\n' % (source, e))
+ sys.exit(1)
+ return seen
+
+
+def write_project(options, f, mappings, sources):
+ targetsrc = ''
+ for source in sorted(sources):
+ action = mappings.get(source)
+ if action:
+ for line in action:
+ f.write(line + '\n')
+ if source.startswith('src/mame/'):
+ targetsrc += ' MAME_DIR .. "%s",\n' % (source, )
+ f.write(
+ '\n' \
+ 'function createProjects_mame_%s(_target, _subtarget)\n' \
+ ' project ("mame_%s")\n' \
+ ' targetsubdir(_target .."_" .. _subtarget)\n' \
+ ' kind (LIBTYPE)\n' \
+ ' uuid (os.uuid("drv-mame-%s"))\n' \
+ ' addprojectflags()\n' \
+ ' \n' \
+ ' includedirs {\n' \
+ ' MAME_DIR .. "src/osd",\n' \
+ ' MAME_DIR .. "src/emu",\n' \
+ ' MAME_DIR .. "src/devices",\n' \
+ ' MAME_DIR .. "src/mame",\n' \
+ ' MAME_DIR .. "src/lib",\n' \
+ ' MAME_DIR .. "src/lib/util",\n' \
+ ' MAME_DIR .. "src/lib/netlist",\n' \
+ ' MAME_DIR .. "3rdparty",\n' \
+ ' GEN_DIR .. "mame/layout",\n' \
+ ' ext_includedir("flac"),\n' \
+ ' ext_includedir("glm"),\n' \
+ ' ext_includedir("jpeg"),\n' \
+ ' ext_includedir("rapidjson"),\n' \
+ ' ext_includedir("zlib"),\n' \
+ ' }\n' \
+ '\n' \
+ ' files{\n%s' \
+ ' }\n' \
+ 'end\n' \
+ '\n' \
+ 'function linkProjects_mame_%s(_target, _subtarget)\n' \
+ ' links {\n' \
+ ' "mame_%s",\n' \
+ ' }\n' \
+ 'end\n' % (options.target, options.target, options.target, targetsrc, options.target, options.target))
+
+
+def write_filter(options, f):
+ drivers = set()
+ for source in options.sources:
+ components = tuple(x for x in split_path(source) if x)
+ if (len(components) > 3) and (components[:3] == ('src', 'mame', 'drivers')):
+ ext = os.path.splitext(components[-1])[1].lower()
+ if ext.startswith('.c'):
+ drivers.add('/'.join(components[3:]))
+ for driver in sorted(drivers):
+ f.write(driver + '\n')
+
+
+if __name__ == '__main__':
+ options = parse_command_line()
+ if options.command == 'sourcesproject':
+ header_to_optional = collect_lua_directives(options)
+ source_dependencies = scan_source_dependencies(options)
+ write_project(options, sys.stdout, header_to_optional, source_dependencies)
+ elif options.command == 'sourcesfilter':
+ write_filter(options, sys.stdout)
+ elif options.command == 'driverlist':
+ DriverFilter(options).write_source(sys.stdout)
diff --git a/scripts/build/makelist.py b/scripts/build/makelist.py
deleted file mode 100644
index 1a27a515e04..00000000000
--- a/scripts/build/makelist.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/python
-##
-## license:BSD-3-Clause
-## copyright-holders:Aaron Giles, Andrew Gardner
-
-from __future__ import with_statement
-
-import sys
-
-drivlist = []
-sourcelist = []
-filter_addlist = []
-filter_removelist = []
-
-def parse_file(srcfile):
- try:
- fp = open(srcfile, 'rt')
- except IOError:
- sys.stderr.write("Unable to open source file '%s'\n" % srcfile)
- return 1
- in_comment = 0
- linenum = 0
- curr_source = ''
- for line in fp.readlines():
- drivname = ''
- linenum+=1
- srcptr = 0
- while srcptr < len(line):
- c = line[srcptr]
- srcptr+=1
- if c==13 or c==10:
- if c==13 and line[srcptr]==10:
- srcptr+=1
- continue
- if c==' ' or c==9:
- continue
- if in_comment==1 and c=='*' and line[srcptr]=='/' :
- srcptr+=1
- in_comment = 0
- continue
- if in_comment:
- continue
- if c=='/' and line[srcptr]=='*' :
- srcptr+=1
- in_comment = 1
- continue
- if c=='/' and line[srcptr]=='/' :
- break
- drivname += c
- drivname = drivname.strip()
- if len(drivname)>0:
- if drivname[0]=='#':
- sys.stderr.write("Importing drivers from '%s'\n" % drivname[1:])
- parse_file(drivname[1:])
- continue
- if drivname[0]=='@':
- curr_source= drivname[8:]
- continue
- if not all(((c >='a' and c<='z') or (c>='0' and c<='9') or c=='_') for c in drivname):
- sys.stderr.write("%s:%d - Invalid character in driver \"%s\"\n" % (srcfile, linenum, drivname))
- return 1
- else:
- if (curr_source == '') or (len(sourcelist)==0) or (curr_source in sourcelist):
- drivlist.append(drivname)
- return 0
-
-def parse_filter_file(srcfile):
- try:
- fp = open(srcfile, 'rt')
- except IOError:
- sys.stderr.write("Unable to open filter file '%s'\n" % srcfile)
- return 1
- in_comment = 0
- linenum = 0
- for line in fp.readlines():
- sourcename = ''
- linenum+=1
- srcptr = 0
- while srcptr < len(line):
- c = line[srcptr]
- srcptr+=1
- if c==13 or c==10:
- if c==13 and line[srcptr]==10:
- srcptr+=1
- continue
- if c==' ' or c==9:
- continue
- if in_comment==1 and c=='*' and line[srcptr]=='/' :
- srcptr+=1
- in_comment = 0
- continue
- if in_comment:
- continue
- if c=='/' and line[srcptr]=='*' :
- srcptr+=1
- in_comment = 1
- continue
- if c=='/' and line[srcptr]=='/' :
- break
- sourcename += c
- sourcename = sourcename.strip()
- if len(sourcename)>0:
- if sourcename[0]=='#':
- sys.stderr.write("Importing drivers from '%s'\n" % sourcename[1:])
- parse_filter_file(sourcename[1:])
- continue
- if sourcename[0]=='+':
- filter_addlist.append(sourcename[1:])
- continue
- if sourcename[0]=='-':
- filter_removelist.append(sourcename[1:])
- continue
- if not all(((c >='a' and c<='z') or (c>='0' and c<='9') or c=='_' or c=='.' or c=='-') for c in sourcename):
- sys.stderr.write("%s:%d - Invalid character in driver \"%s\"\n" % (srcfile, linenum, sourcename))
- return 1
- else:
- sourcelist.append(sourcename)
- return 0
-
-
-if len(sys.argv) < 2 or len(sys.argv) > 3:
- print('Usage:')
- print(' makelist <source.lst> [<filter.flt>]')
- sys.exit(0)
-
-if len(sys.argv) == 3:
- if parse_filter_file(sys.argv[2]) :
- sys.exit(1)
- sys.stderr.write("%d source file(s) found\n" % len(sourcelist))
-
-if parse_file(sys.argv[1]) :
- sys.exit(1)
-
-# output a count
-if len(drivlist)==0 :
- sys.stderr.write("No drivers found\n")
- sys.exit(1)
-
-for x in filter_addlist:
- drivlist.append(x)
-
-drivlist = [x for x in drivlist if (x not in filter_removelist)]
-
-sys.stderr.write("%d driver(s) found\n" % len(drivlist))
-
-# add a reference to the ___empty driver
-drivlist.append("___empty")
-
-# start with a header
-print('#include "emu.h"\n')
-print('#include "drivenum.h"\n')
-
-#output the list of externs first
-for drv in sorted(drivlist):
- print("GAME_EXTERN(%s);" % drv)
-print("")
-
-# then output the array
-print("const game_driver * const driver_list::s_drivers_sorted[%d] =" % len(drivlist))
-print("{")
-for drv in sorted(drivlist):
- print("\t&GAME_NAME(%s)," % drv)
-print("};")
-print("")
-
-# also output a global count
-print("std::size_t const driver_list::s_driver_count = %d;\n" % len(drivlist))
diff --git a/scripts/genie.lua b/scripts/genie.lua
index 734508a04f2..fe5b8930f3f 100644
--- a/scripts/genie.lua
+++ b/scripts/genie.lua
@@ -1530,15 +1530,17 @@ configuration { }
if (_OPTIONS["SOURCES"] ~= nil) then
local str = _OPTIONS["SOURCES"]
+ local sourceargs = ""
for word in string.gmatch(str, '([^,]+)') do
- if (not os.isfile(path.join(MAME_DIR ,word))) then
+ if (not os.isfile(path.join(MAME_DIR, word))) then
print("File " .. word.. " does not exist")
os.exit()
end
+ sourceargs = sourceargs .. " " .. word
end
- OUT_STR = os.outputof( PYTHON .. " " .. MAME_DIR .. "scripts/build/makedep.py " .. MAME_DIR .. " " .. _OPTIONS["SOURCES"] .. " target " .. _OPTIONS["subtarget"])
+ OUT_STR = os.outputof( PYTHON .. " " .. MAME_DIR .. "scripts/build/makedep.py sourcesproject -r " .. MAME_DIR .. " -t " .. _OPTIONS["subtarget"] .. sourceargs )
load(OUT_STR)()
- os.outputof( PYTHON .. " " .. MAME_DIR .. "scripts/build/makedep.py " .. MAME_DIR .. " " .. _OPTIONS["SOURCES"] .. " drivers " .. _OPTIONS["subtarget"] .. " > ".. GEN_DIR .. _OPTIONS["target"] .. "/" .. _OPTIONS["subtarget"]..".flt")
+ os.outputof( PYTHON .. " " .. MAME_DIR .. "scripts/build/makedep.py sourcesfilter" .. sourceargs .. " > ".. GEN_DIR .. _OPTIONS["target"] .. "/" .. _OPTIONS["subtarget"] .. ".flt" )
end
group "libs"
diff --git a/scripts/minimaws/minimaws.wsgi b/scripts/minimaws/minimaws.wsgi
index ff6d045419f..1ddab440be4 100644
--- a/scripts/minimaws/minimaws.wsgi
+++ b/scripts/minimaws/minimaws.wsgi
@@ -3,13 +3,14 @@
## license:BSD-3-Clause
## copyright-holders:Vas Crabb
##
-## Simple script for deploying minimaws with mod_wsgi.
+## Simple wrapper for deploying minimaws with mod_wsgi.
import os.path
import sys
-sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+scriptdir = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, scriptdir)
import lib.wsgiserve
-application = lib.wsgiserve.MiniMawsApp(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'minimaws.sqlite3'))
+application = lib.wsgiserve.MiniMawsApp(os.path.join(scriptdir, 'minimaws.sqlite3'))
diff --git a/scripts/src/main.lua b/scripts/src/main.lua
index ad0e1a1d08c..992ac602168 100644
--- a/scripts/src/main.lua
+++ b/scripts/src/main.lua
@@ -380,12 +380,12 @@ if (STANDALONE~=true) then
GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", MAME_DIR .. "src/".._target .."/" .. _target ..".lst", true },
}
custombuildtask {
- { MAME_DIR .. "src/".._target .."/" .. _subtarget ..".flt" , GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makelist.py", MAME_DIR .. "src/".._target .."/" .. _target ..".lst" }, {"@echo Building driver list...", PYTHON .. " $(1) $(2) $(<) > $(@)" }},
+ { MAME_DIR .. "src/".._target .."/" .. _subtarget ..".flt" , GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makedep.py", MAME_DIR .. "src/".._target .."/" .. _target ..".lst" }, {"@echo Building driver list...", PYTHON .. " $(1) driverlist $(2) -f $(<) > $(@)" }},
}
else
if os.isfile(MAME_DIR .. "src/".._target .."/" .. _subtarget ..".lst") then
custombuildtask {
- { MAME_DIR .. "src/".._target .."/" .. _subtarget ..".lst" , GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makelist.py" }, {"@echo Building driver list...", PYTHON .. " $(1) $(<) > $(@)" }},
+ { MAME_DIR .. "src/".._target .."/" .. _subtarget ..".lst" , GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makedep.py" }, {"@echo Building driver list...", PYTHON .. " $(1) driverlist $(<) > $(@)" }},
}
else
dependency {
@@ -393,7 +393,7 @@ if (STANDALONE~=true) then
GEN_DIR .. _target .. "/" .. _target .."/drivlist.cpp", MAME_DIR .. "src/".._target .."/" .. _target ..".lst", true },
}
custombuildtask {
- { MAME_DIR .. "src/".._target .."/" .. _target ..".lst" , GEN_DIR .. _target .. "/" .. _target .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makelist.py" }, {"@echo Building driver list...", PYTHON .. " $(1) $(<) > $(@)" }},
+ { MAME_DIR .. "src/".._target .."/" .. _target ..".lst" , GEN_DIR .. _target .. "/" .. _target .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makedep.py" }, {"@echo Building driver list...", PYTHON .. " $(1) driverlist $(<) > $(@)" }},
}
end
end
@@ -405,7 +405,7 @@ if (STANDALONE~=true) then
GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", MAME_DIR .. "src/".._target .."/" .. _target ..".lst", true },
}
custombuildtask {
- { GEN_DIR .. _target .."/" .. _subtarget ..".flt" , GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makelist.py", MAME_DIR .. "src/".._target .."/" .. _target ..".lst" }, {"@echo Building driver list...", PYTHON .. " $(1) $(2) $(<) > $(@)" }},
+ { GEN_DIR .. _target .."/" .. _subtarget ..".flt" , GEN_DIR .. _target .. "/" .. _subtarget .."/drivlist.cpp", { MAME_DIR .. "scripts/build/makedep.py", MAME_DIR .. "src/".._target .."/" .. _target ..".lst" }, {"@echo Building driver list...", PYTHON .. " $(1) driverlist $(2) -f $(<) > $(@)" }},
}
end
diff --git a/src/tools/srcclean.cpp b/src/tools/srcclean.cpp
index 431bc00434c..331eab21bae 100644
--- a/src/tools/srcclean.cpp
+++ b/src/tools/srcclean.cpp
@@ -24,10 +24,12 @@
#define MY_MACRO \
"string that \
continues"
- * Will not produce expected output for a string continuation that
- breaks an escape sequence, e.g. this:
- "bad\\
- tbehaviour"
+ * Numeric literals broken by line continuations are not recognised
+ * Will not recognise a comment delimiter broken by multiple line
+ continuations. e.g. this:
+ /\
+ \
+ / preprocessor abuse
Known Lua limitations:
* Whitespace normalisation is applied inside long string literals
@@ -868,19 +870,19 @@ private:
bool tail_is(char32_t ch) const
{
- return !m_tail.empty() && (m_tail.front() == ch);
+ return !m_tail.empty() && (m_tail.back() == ch);
}
void pop_tail()
{
if (!m_tail.empty())
- m_tail.pop_front();
+ m_tail.pop_back();
}
void replace_tail(char32_t ch)
{
assert(!m_tail.empty());
- *m_tail.begin() = ch;
+ m_tail.back() = ch;
}
void flush_tail()
@@ -938,10 +940,12 @@ private:
bool m_escape = false;
std::deque<char32_t> m_tail;
std::uint64_t m_comment_line = 0U;
+ bool m_broken_escape = false;
char32_t m_lead_digit = 0U;
unsigned m_radix = 0U;
std::uint64_t m_tabs_escaped = 0U;
+ std::uint64_t m_broken_comment_delimiters = 0U;
std::uint64_t m_line_comment_continuations = 0U;
std::uint64_t m_string_continuations = 0U;
std::uint64_t m_uppercase_radix = 0U;
@@ -965,6 +969,7 @@ bool cpp_cleaner::affected() const
return
cleaner_base::affected() ||
m_tabs_escaped ||
+ m_broken_comment_delimiters ||
m_line_comment_continuations ||
m_string_continuations ||
m_uppercase_radix ||
@@ -977,6 +982,8 @@ void cpp_cleaner::summarise(std::ostream &os) const
cleaner_base::summarise(os);
if (m_tabs_escaped)
util::stream_format(os, "%1$u tab(s) escaped\n", m_tabs_escaped);
+ if (m_broken_comment_delimiters)
+ util::stream_format(os, "%1$u broken comment delimiter(s) replaced\n", m_broken_comment_delimiters);
if (m_line_comment_continuations)
util::stream_format(os, "%1$u line comment continuation(s) replaced\n", m_line_comment_continuations);
if (m_string_continuations)
@@ -1016,16 +1023,17 @@ void cpp_cleaner::output_character(char32_t ch)
switch (ch)
{
+ case HORIZONTAL_TAB:
+ case SPACE:
+ case BACKSLASH:
+ m_tail.emplace_back(ch);
+ break;
default:
flush_tail();
if (LINE_FEED == ch)
- {
cleaner_base::output_character(ch);
- break;
- }
- case HORIZONTAL_TAB:
- case SPACE:
- m_tail.emplace_back(ch);
+ else
+ m_tail.emplace_back(ch);
}
}
@@ -1085,6 +1093,13 @@ void cpp_cleaner::process_default(char32_t ch)
{
switch (ch)
{
+ case LINE_FEED:
+ if (m_escape && tail_is(BACKSLASH))
+ {
+ m_broken_escape = true;
+ return;
+ }
+ break;
case DOUBLE_QUOTE:
m_parse_state = parse_state::STRING_CONSTANT;
break;
@@ -1097,11 +1112,35 @@ void cpp_cleaner::process_default(char32_t ch)
m_parse_state = parse_state::COMMENT;
m_comment_line = m_input_line;
set_tab_limit();
+ if (m_broken_escape)
+ {
+ ++m_broken_comment_delimiters;
+ assert(tail_is(BACKSLASH));
+ pop_tail();
+ output_character(ch);
+ output_character(LINE_FEED);
+ m_escape = false;
+ m_broken_escape = false;
+ return;
+ }
}
break;
case SLASH:
if (m_escape)
+ {
m_parse_state = parse_state::LINE_COMMENT;
+ if (m_broken_escape)
+ {
+ ++m_broken_comment_delimiters;
+ assert(tail_is(BACKSLASH));
+ pop_tail();
+ assert(tail_is(SLASH));
+ pop_tail();
+ output_character(LINE_FEED);
+ output_character(SLASH);
+ m_broken_escape = false;
+ }
+ }
break;
default:
if (is_token_lead(ch))
@@ -1112,11 +1151,15 @@ void cpp_cleaner::process_default(char32_t ch)
{
m_parse_state = parse_state::NUMERIC_CONSTANT;
m_escape = false;
+ m_broken_escape = false;
process_numeric(ch);
return;
}
}
- m_escape = (SLASH == ch) ? !m_escape : false;
+ if (m_broken_escape)
+ output_character(LINE_FEED);
+ m_escape = m_escape ? ((BACKSLASH == ch) && tail_is(SLASH)) : (SLASH == ch);
+ m_broken_escape = false;
output_character(ch);
}
@@ -1125,18 +1168,65 @@ void cpp_cleaner::process_comment(char32_t ch)
{
switch (ch)
{
- case SLASH:
- if (m_escape)
+ case LINE_FEED:
+ if (m_escape && tail_is(BACKSLASH))
+ {
+ m_broken_escape = true;
+ }
+ else
{
m_escape = false;
+ m_broken_escape = false;
+ output_character(ch);
+ }
+ break;
+ case SLASH:
+ if (m_broken_escape)
+ {
m_parse_state = parse_state::DEFAULT;
m_comment_line = 0U;
+ ++m_broken_comment_delimiters;
+ assert(tail_is(BACKSLASH));
+ pop_tail();
+ assert(tail_is(ASTERISK));
+ pop_tail();
+ output_character(LINE_FEED);
+ output_character(ASTERISK);
output_character(ch);
reset_tab_limit();
- break;
}
+ else if (m_escape)
+ {
+ m_parse_state = parse_state::DEFAULT;
+ m_comment_line = 0U;
+ output_character(ch);
+ reset_tab_limit();
+ }
+ else
+ {
+ output_character(ch);
+ }
+ m_escape = false;
+ m_broken_escape = false;
+ break;
+ case BACKSLASH:
+ if (m_broken_escape)
+ {
+ m_escape = false;
+ m_broken_escape = false;
+ output_character(LINE_FEED);
+ }
+ else if (m_escape)
+ {
+ m_escape = tail_is(ASTERISK);
+ }
+ output_character(ch);
+ break;
default:
+ if (m_broken_escape)
+ output_character(LINE_FEED);
m_escape = ASTERISK == ch;
+ m_broken_escape = false;
output_character(ch);
}
}
@@ -1195,9 +1285,24 @@ void cpp_cleaner::process_text(char32_t ch)
else if (tail_is(BACKSLASH))
{
++m_string_continuations;
- replace_tail(DOUBLE_QUOTE);
- output_character(ch);
- output_character(DOUBLE_QUOTE);
+ if (m_escape)
+ {
+ replace_tail(DOUBLE_QUOTE);
+ output_character(ch);
+ output_character(DOUBLE_QUOTE);
+ }
+ else
+ {
+ pop_tail();
+ assert(tail_is(BACKSLASH));
+ pop_tail();
+ output_character(DOUBLE_QUOTE);
+ output_character(ch);
+ output_character(DOUBLE_QUOTE);
+ output_character(BACKSLASH);
+ m_escape = true;
+ return;
+ }
}
else
{