# 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. # Original: https://github.com/taniwha/cfgnode # 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): self.filename = filename if text[0:3] == "\xef\xbb\xbf": text = text[3:] self.text = text self.single = single self.quotes = quotes self.pos = 0 self.line = 1 self.unget = False self.token = None def error(self, msg): raise ScriptError(self.filename, self.line, msg) def token_available(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 get_line(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 get_token(self, crossline=False): if self.unget: self.unget = False return self.token if not self.token_available(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": 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 unget_token(self): self.unget = True