quakeforge/tools/io_qfmap/script.py
Bill Currie 6e8a3b8153 [qfmap] Parse field info from quaked comments
Id's comments are a little inconsistent, but for the most part usable
info can be extracted. While not yet supported, Arcane Dimensions'
comments are extremely consistent (just some issues with hyphen counts
in separators), so parsing out usable info will be fairly easy. The hard
part will be presenting it.
2022-09-22 09:35:56 +09:00

126 lines
4.6 KiB
Python

# vim:ts=4:et
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
class ScriptError(Exception):
def __init__(self, fname, line, message):
Exception.__init__(self, "%s:%d: %s" % (fname, line, message))
self.line = line
class Script:
def __init__(self, filename, text, single="{}()':", quotes=True):
if text[0:3] == "\xef\xbb\xbf":
text = text[3:]
elif text[0] == u"\ufeff":
text = text[1:]
self.token = ""
self.unget = False
self.text = text
self.pos = 0
self.filename = filename
self.line = 1
self.no_quote_lines = False
self.single = single
self.quotes = quotes
def error(self, msg):
raise ScriptError(self.filename, self.line, msg)
def tokenAvailable(self, crossline=False):
if self.unget:
return True
while self.pos < len(self.text):
while self.pos < len(self.text) and self.text[self.pos].isspace():
if self.text[self.pos] == "\n":
if not crossline:
return False
self.line += 1
self.pos += 1
if self.pos == len(self.text):
return False
if self.text[self.pos] in ["\x1a", "\x04"]:
# end of file characters
self.pos += 1
continue
if self.text[self.pos:self.pos + 2] == "//":
while (self.pos < len(self.text)
and self.text[self.pos] != "\n"):
self.pos += 1
if self.pos == len(self.text):
return False
if not crossline:
return False
continue
return True
return False
def getLine(self):
start = self.pos
end = start
while self.pos < len(self.text):
if self.text[self.pos] == "\n":
self.line += 1
self.pos += 1
break
if self.text[self.pos:self.pos + 2] == "//":
break
self.pos += 1
end = self.pos
if self.unget:
self.unget = False
self.token = self.token + self.text[start:end]
else:
self.token = self.text[start:end]
return self.pos < len(self.text)
def getToken(self, crossline=False):
if self.unget:
self.unget = False
return self.token
if not self.tokenAvailable(crossline):
if not crossline:
self.error("line is incomplete")
return None
if self.quotes and self.text[self.pos] == "\"":
self.pos += 1
start = self.pos
if self.text[self.pos] == len(self.text):
self.error("EOF inside quoted string")
while self.text[self.pos] != "\"":
if self.pos == len(self.text):
self.error("EOF inside quoted string")
return None
if self.text[self.pos] == "\n":
if self.no_quote_lines:
self.error("EOL inside quoted string")
return None
self.line += 1
self.pos += 1
self.token = self.text[start:self.pos]
self.pos += 1
else:
start = self.pos
if self.text[self.pos] in self.single:
self.pos += 1
else:
while (self.pos < len(self.text)
and not self.text[self.pos].isspace()
and self.text[self.pos] not in self.single):
self.pos += 1
self.token = self.text[start:self.pos]
return self.token
def ungetToken(self):
self.unget = True